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  }