github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/httputil/auth_test.go (about)

     1  /*
     2  Copyright 2013 The Camlistore Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package httputil
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"net"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"testing"
    26  )
    27  
    28  func testServer(t *testing.T, l net.Listener) *httptest.Server {
    29  	ts := &httptest.Server{
    30  		Listener: l,
    31  		Config: &http.Server{
    32  			Handler: http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
    33  				if IsLocalhost(r) {
    34  					fmt.Fprintf(rw, "authorized")
    35  					return
    36  				}
    37  				fmt.Fprintf(rw, "unauthorized")
    38  			}),
    39  		},
    40  	}
    41  	ts.Start()
    42  
    43  	return ts
    44  }
    45  
    46  func TestLocalhostAuthIPv6(t *testing.T) {
    47  	l, err := net.Listen("tcp", "[::1]:0")
    48  	if err != nil {
    49  		t.Skip("skipping IPv6 test; can't listen on [::1]:0")
    50  	}
    51  	_, port, err := net.SplitHostPort(l.Addr().String())
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  
    56  	// See if IPv6 works on this machine first. It seems the above
    57  	// Listen can pass on Linux but fail here in the dial.
    58  	c, err := net.Dial("tcp6", l.Addr().String())
    59  	if err != nil {
    60  		t.Skipf("skipping IPv6 test; dial back to %s failed with %v", l.Addr(), err)
    61  	}
    62  	c.Close()
    63  
    64  	ts := testServer(t, l)
    65  	defer ts.Close()
    66  
    67  	// Use an explicit transport to force IPv6 (http.Get resolves localhost in IPv4 otherwise)
    68  	trans := &http.Transport{
    69  		Dial: func(network, addr string) (net.Conn, error) {
    70  			c, err := net.Dial("tcp6", addr)
    71  			return c, err
    72  		},
    73  	}
    74  
    75  	testLoginRequest(t, &http.Client{Transport: trans}, "http://[::1]:"+port)
    76  
    77  	// See if we can get an IPv6 from resolving localhost
    78  	localips, err := net.LookupIP("localhost")
    79  	if err != nil {
    80  		t.Skipf("skipping IPv6 test; resolving localhost failed with %v", err)
    81  	}
    82  	if hasIPv6(localips) {
    83  		testLoginRequest(t, &http.Client{Transport: trans}, "http://localhost:"+port)
    84  	} else {
    85  		t.Logf("incomplete IPv6 test; resolving localhost didn't return any IPv6 addresses")
    86  	}
    87  }
    88  
    89  func hasIPv6(ips []net.IP) bool {
    90  	for _, ip := range ips {
    91  		if ip.To4() == nil {
    92  			return true
    93  		}
    94  	}
    95  	return false
    96  }
    97  
    98  func TestLocalhostAuthIPv4(t *testing.T) {
    99  	l, err := net.Listen("tcp", "127.0.0.1:0")
   100  	if err != nil {
   101  		t.Skip("skipping IPv4 test; can't listen on 127.0.0.1:0")
   102  	}
   103  	_, port, err := net.SplitHostPort(l.Addr().String())
   104  	if err != nil {
   105  		t.Fatal(err)
   106  	}
   107  
   108  	ts := testServer(t, l)
   109  	defer ts.Close()
   110  
   111  	testLoginRequest(t, &http.Client{}, "http://127.0.0.1:"+port)
   112  	testLoginRequest(t, &http.Client{}, "http://localhost:"+port)
   113  }
   114  
   115  func testLoginRequest(t *testing.T, client *http.Client, URL string) {
   116  	res, err := client.Get(URL)
   117  	if err != nil {
   118  		t.Fatal(err)
   119  	}
   120  	body, err := ioutil.ReadAll(res.Body)
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	const exp = "authorized"
   125  	if string(body) != exp {
   126  		t.Errorf("got %q (instead of %v)", string(body), exp)
   127  	}
   128  }
   129  
   130  func TestBasicAuth(t *testing.T) {
   131  	for _, d := range []struct {
   132  		header string
   133  		u, pw  string
   134  		valid  bool
   135  	}{
   136  		// Empty is invalid.
   137  		{},
   138  		{
   139  			// Missing password.
   140  			header: "Basic QWxhZGRpbg==",
   141  		},
   142  		{
   143  			// Malformed base64 encoding.
   144  			header: "Basic foo",
   145  		},
   146  		{
   147  			// Malformed header, no 'Basic ' prefix.
   148  			header: "QWxhZGRpbg==",
   149  		},
   150  		{
   151  			header: "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
   152  			u:      "Aladdin",
   153  			pw:     "open sesame",
   154  			valid:  true,
   155  		},
   156  	} {
   157  		req, err := http.NewRequest("GET", "/", nil)
   158  		if err != nil {
   159  			t.Fatal(err)
   160  		}
   161  		if d.header != "" {
   162  			req.Header.Set("Authorization", d.header)
   163  		}
   164  
   165  		u, pw, err := BasicAuth(req)
   166  		t.Log(d.header, err)
   167  		if d.valid && err != nil {
   168  			t.Error("Want success parse of auth header, got", err)
   169  		}
   170  		if !d.valid && err == nil {
   171  			t.Error("Want error parsing", d.header)
   172  		}
   173  
   174  		if d.u != u {
   175  			t.Errorf("Want user %q, got %q", d.u, u)
   176  		}
   177  
   178  		if d.pw != pw {
   179  			t.Errorf("Want password %q, got %q", d.pw, pw)
   180  		}
   181  	}
   182  }