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 }