github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/api/state_macaroon_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package api_test 5 6 import ( 7 "net/url" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/api" 14 apitesting "github.com/juju/juju/api/testing" 15 "github.com/juju/juju/permission" 16 "github.com/juju/juju/rpc" 17 ) 18 19 var _ = gc.Suite(&macaroonLoginSuite{}) 20 21 type macaroonLoginSuite struct { 22 apitesting.MacaroonSuite 23 client api.Connection 24 } 25 26 const testUserName = "testuser@somewhere" 27 28 func (s *macaroonLoginSuite) SetUpTest(c *gc.C) { 29 s.MacaroonSuite.SetUpTest(c) 30 s.AddModelUser(c, testUserName) 31 s.AddControllerUser(c, testUserName, permission.LoginAccess) 32 info := s.APIInfo(c) 33 info.SkipLogin = true 34 s.client = s.OpenAPI(c, info, nil) 35 } 36 37 func (s *macaroonLoginSuite) TearDownTest(c *gc.C) { 38 s.client.Close() 39 s.MacaroonSuite.TearDownTest(c) 40 } 41 42 func (s *macaroonLoginSuite) TestSuccessfulLogin(c *gc.C) { 43 s.DischargerLogin = func() string { return testUserName } 44 err := s.client.Login(nil, "", "", nil) 45 c.Assert(err, jc.ErrorIsNil) 46 } 47 48 func (s *macaroonLoginSuite) TestFailedToObtainDischargeLogin(c *gc.C) { 49 err := s.client.Login(nil, "", "", nil) 50 c.Assert(err, gc.ErrorMatches, `cannot get discharge from "https://.*": third party refused discharge: cannot discharge: login denied by discharger`) 51 } 52 53 func (s *macaroonLoginSuite) TestUnknownUserLogin(c *gc.C) { 54 s.DischargerLogin = func() string { 55 return "testUnknown" 56 } 57 err := s.client.Login(nil, "", "", nil) 58 c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ 59 Message: "invalid entity name or password", 60 Code: "unauthorized access", 61 }) 62 } 63 64 func (s *macaroonLoginSuite) TestConnectStream(c *gc.C) { 65 catcher := urlCatcher{} 66 s.PatchValue(api.WebsocketDialConfig, catcher.recordLocation) 67 68 dischargeCount := 0 69 s.DischargerLogin = func() string { 70 dischargeCount++ 71 return testUserName 72 } 73 // First log into the regular API. 74 err := s.client.Login(nil, "", "", nil) 75 c.Assert(err, jc.ErrorIsNil) 76 c.Assert(dischargeCount, gc.Equals, 1) 77 78 // Then check that ConnectStream works OK and that it doesn't need 79 // to discharge again. 80 conn, err := s.client.ConnectStream("/path", nil) 81 c.Assert(err, gc.IsNil) 82 defer conn.Close() 83 connectURL := catcher.location 84 c.Assert(connectURL.Path, gc.Equals, "/model/"+s.State.ModelTag().Id()+"/path") 85 c.Assert(dischargeCount, gc.Equals, 1) 86 } 87 88 func (s *macaroonLoginSuite) TestConnectStreamWithoutLogin(c *gc.C) { 89 catcher := urlCatcher{} 90 s.PatchValue(api.WebsocketDialConfig, catcher.recordLocation) 91 92 conn, err := s.client.ConnectStream("/path", nil) 93 c.Assert(err, gc.ErrorMatches, `cannot use ConnectStream without logging in`) 94 c.Assert(conn, gc.Equals, nil) 95 } 96 97 func (s *macaroonLoginSuite) TestConnectStreamFailedDischarge(c *gc.C) { 98 // This is really a test for ConnectStream, but to test ConnectStream's 99 // discharge failing logic, we need an actual endpoint to test against, 100 // and the debug-log endpoint makes a convenient example. 101 102 var dischargeError bool 103 s.DischargerLogin = func() string { 104 if dischargeError { 105 return "" 106 } 107 return testUserName 108 } 109 110 // Make an API connection that uses a cookie jar 111 // that allows us to remove all cookies. 112 jar := apitesting.NewClearableCookieJar() 113 client := s.OpenAPI(c, nil, jar) 114 115 // Ensure that the discharger won't discharge and try 116 // logging in again. We should succeed in getting past 117 // authorization because we have the cookies (but 118 // the actual debug-log endpoint will return an error). 119 dischargeError = true 120 logArgs := url.Values{"noTail": []string{"true"}} 121 conn, err := client.ConnectStream("/log", logArgs) 122 c.Assert(err, jc.ErrorIsNil) 123 c.Assert(conn, gc.NotNil) 124 conn.Close() 125 126 // Then delete all the cookies by deleting the cookie jar 127 // and try again. The login should fail. 128 jar.Clear() 129 130 conn, err = client.ConnectStream("/log", logArgs) 131 c.Assert(err, gc.ErrorMatches, `cannot get discharge from "https://.*": third party refused discharge: cannot discharge: login denied by discharger`) 132 c.Assert(conn, gc.IsNil) 133 }