github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/httpcontext/auth_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package httpcontext_test
     5  
     6  import (
     7  	"errors"
     8  	"io"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"net/http/httptest"
    12  
    13  	"github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  	"gopkg.in/juju/names.v2"
    17  
    18  	"github.com/juju/juju/apiserver/httpcontext"
    19  	"github.com/juju/juju/apiserver/params"
    20  )
    21  
    22  type BasicAuthHandlerSuite struct {
    23  	testing.IsolationSuite
    24  	stub     testing.Stub
    25  	handler  *httpcontext.BasicAuthHandler
    26  	authInfo httpcontext.AuthInfo
    27  	server   *httptest.Server
    28  }
    29  
    30  var _ = gc.Suite(&BasicAuthHandlerSuite{})
    31  
    32  func (s *BasicAuthHandlerSuite) SetUpTest(c *gc.C) {
    33  	s.IsolationSuite.SetUpTest(c)
    34  	s.stub.ResetCalls()
    35  	s.handler = &httpcontext.BasicAuthHandler{
    36  		Authenticator: s,
    37  		Authorizer:    s,
    38  		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    39  			authInfo, ok := httpcontext.RequestAuthInfo(r)
    40  			if !ok || authInfo != s.authInfo {
    41  				w.WriteHeader(http.StatusBadRequest)
    42  			} else {
    43  				w.WriteHeader(http.StatusOK)
    44  				io.WriteString(w, "hullo!")
    45  			}
    46  		}),
    47  	}
    48  	s.server = httptest.NewServer(s.handler)
    49  	s.authInfo = httpcontext.AuthInfo{
    50  		Entity: &mockEntity{tag: names.NewUserTag("bob")},
    51  	}
    52  }
    53  
    54  func (s *BasicAuthHandlerSuite) Authenticate(req *http.Request) (httpcontext.AuthInfo, error) {
    55  	s.stub.MethodCall(s, "Authenticate", req)
    56  	if err := s.stub.NextErr(); err != nil {
    57  		return httpcontext.AuthInfo{}, err
    58  	}
    59  	return s.authInfo, nil
    60  }
    61  
    62  func (s *BasicAuthHandlerSuite) AuthenticateLoginRequest(
    63  	serverHost, modelUUID string, req params.LoginRequest,
    64  ) (httpcontext.AuthInfo, error) {
    65  	panic("should not be called")
    66  }
    67  
    68  func (s *BasicAuthHandlerSuite) Authorize(authInfo httpcontext.AuthInfo) error {
    69  	s.stub.MethodCall(s, "Authorize", authInfo)
    70  	return s.stub.NextErr()
    71  }
    72  
    73  func (s *BasicAuthHandlerSuite) TestRequestAuthInfoNoContext(c *gc.C) {
    74  	_, ok := httpcontext.RequestAuthInfo(&http.Request{})
    75  	c.Assert(ok, jc.IsFalse)
    76  }
    77  
    78  func (s *BasicAuthHandlerSuite) TestSuccess(c *gc.C) {
    79  	resp, err := s.server.Client().Get(s.server.URL)
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
    82  	defer resp.Body.Close()
    83  	out, err := ioutil.ReadAll(resp.Body)
    84  	c.Assert(string(out), gc.Equals, "hullo!")
    85  	s.stub.CheckCallNames(c, "Authenticate", "Authorize")
    86  }
    87  
    88  func (s *BasicAuthHandlerSuite) TestAuthenticationFailure(c *gc.C) {
    89  	s.stub.SetErrors(errors.New("username/password invalid"))
    90  
    91  	resp, err := s.server.Client().Get(s.server.URL)
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	c.Assert(resp.StatusCode, gc.Equals, http.StatusUnauthorized)
    94  	defer resp.Body.Close()
    95  
    96  	out, err := ioutil.ReadAll(resp.Body)
    97  	c.Assert(string(out), gc.Equals, "authentication failed: username/password invalid\n")
    98  	c.Assert(resp.Header.Get("WWW-Authenticate"), gc.Equals, `Basic realm="juju"`)
    99  	s.stub.CheckCallNames(c, "Authenticate")
   100  }
   101  
   102  func (s *BasicAuthHandlerSuite) TestAuthorizationFailure(c *gc.C) {
   103  	s.stub.SetErrors(nil, errors.New("unauthorized access for resource"))
   104  
   105  	resp, err := s.server.Client().Get(s.server.URL)
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	c.Assert(resp.StatusCode, gc.Equals, http.StatusForbidden)
   108  	defer resp.Body.Close()
   109  	out, err := ioutil.ReadAll(resp.Body)
   110  	c.Assert(string(out), gc.Equals, "authorization failed: unauthorized access for resource\n")
   111  	s.stub.CheckCallNames(c, "Authenticate", "Authorize")
   112  }
   113  
   114  func (s *BasicAuthHandlerSuite) TestAuthorizationOptional(c *gc.C) {
   115  	s.handler.Authorizer = nil
   116  
   117  	resp, err := s.server.Client().Get(s.server.URL)
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
   120  	defer resp.Body.Close()
   121  }
   122  
   123  type mockEntity struct {
   124  	tag names.Tag
   125  }
   126  
   127  func (e *mockEntity) Tag() names.Tag {
   128  	return e.tag
   129  }