-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing cookie based authentication #1091
base: main
Are you sure you want to change the base?
Changes from all commits
9acfabf
b675a0b
150d0b6
02adced
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -256,7 +256,8 @@ async def connect( | |
specified_facades=None, | ||
proxy=None, | ||
debug_log_conn=None, | ||
debug_log_params={} | ||
debug_log_params={}, | ||
cookie_domain=None, | ||
): | ||
"""Connect to the websocket. | ||
|
||
|
@@ -285,8 +286,10 @@ async def connect( | |
to prevent using the conservative client pinning with in the client. | ||
:param TextIOWrapper debug_log_conn: target if this is a debug log connection | ||
:param dict debug_log_params: filtering parameters for the debug-log output | ||
:param str cookie_domain: Which domain the controller uses for cookies. | ||
""" | ||
self = cls() | ||
self.cookie_domain = cookie_domain | ||
if endpoint is None: | ||
raise ValueError('no endpoint provided') | ||
if not isinstance(endpoint, str) and not isinstance(endpoint, list): | ||
|
@@ -301,7 +304,7 @@ async def connect( | |
if password is not None: | ||
raise errors.JujuAuthError('cannot log in as external ' | ||
'user with a password') | ||
username = None | ||
|
||
self.usertag = tag.user(username) | ||
self.password = password | ||
|
||
|
@@ -762,6 +765,7 @@ def connect_params(self): | |
'bakery_client': self.bakery_client, | ||
'max_frame_size': self.max_frame_size, | ||
'proxy': self.proxy, | ||
'cookie_domain': self.cookie_domain, | ||
} | ||
|
||
async def controller(self): | ||
|
@@ -774,6 +778,7 @@ async def controller(self): | |
cacert=self.cacert, | ||
bakery_client=self.bakery_client, | ||
max_frame_size=self.max_frame_size, | ||
cookie_domain=self.cookie_domain, | ||
) | ||
|
||
async def reconnect(self): | ||
|
@@ -871,7 +876,7 @@ async def _connect_with_login(self, endpoints): | |
# a few times. | ||
for i in range(0, 2): | ||
result = (await self.login())['response'] | ||
macaroonJSON = result.get('discharge-required') | ||
macaroonJSON = result.get('bakery-discharge-required') | ||
if macaroonJSON is None: | ||
self.info = result | ||
success = True | ||
|
@@ -962,7 +967,7 @@ async def login(self): | |
params['credentials'] = self.password | ||
else: | ||
macaroons = _macaroons_for_domain(self.bakery_client.cookies, | ||
self.endpoint) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I fully get the intent behind this from inspection. What is the difference here between the endpoint and the cookie domain? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is because when you are using macaroons from the bakery client, you are actually using cookies that were originally put in the cookie jar by the juju client. The juju client does not use the endpoint as the cookie domain. Instead it uses either the controller's UUID (if the controller is self signed) or its SNIHostName. If we don't pick the correct cookie domain then pylibjuju will not find the cookie and it will fail to authenticate with the controller. I believe this is because if you have a self signed HA controller (for example) then there will be three different potential endpoints, so if you use that for your cookie domain, then your coookie will only work with one of the endpoints. As an example: you might have an endpoint which is 192.168.3.14, but the cookie in the jar has the domain "791fa163-16bd-4726-9c58-7c360cc133b2". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah fair, good work on the digging! Seems like a bug that this wasn't implemented the same way then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct, the juju code is
where PreferredHost is either the SNIHostName or controller UUID. |
||
self.cookie_domain) | ||
params['macaroons'] = [[bakery.macaroon_to_dict(m) for m in ms] | ||
for ms in macaroons] | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the casual observer - newer Juju controllers (2.9 onwards) use the "bakery-discharge-required" attribute.