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