Skip to content
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

feat(cmd-register): prevent replacing existing controller if logged in #18079

Open
wants to merge 1 commit into
base: 3.5
Choose a base branch
from

Conversation

ca-scribner
Copy link
Contributor

@ca-scribner ca-scribner commented Sep 11, 2024

This PR adds additional checks to juju register to block users from adding a known controller. The changes proposed here:

  • prevent users from hitting lp2073741 by adding validation coverage
  • improve the UX in some failure cases by raising the error before consuming the user's registration token and/or before we prompt them for a password

Checklist

  • Code style: imports ordered, good names, simple structure, etc
  • Comments saying why design decisions were made
  • Go unit tests, with comments saying what you're testing
  • Integration tests, with comments saying what you're testing
  • doc.go added or updated in changed packages

QA steps

On computer 1 (with a juju controller):

juju add-user u1
juju add-user u2

On computer 2 (without a juju controller):

juju register TOKEN_FROM_u1
>> works
juju register TOKEN_FROM_u2 [--replace]
>> error with instructions.  This should not burn `TOKEN_FROM_u2`
juju logout -c CONTROLLER
juju register TOKEN_FROM_u2 --replace
>> should work, including the TOKEN_FROM_u2 still being valid

Documentation changes

Minor change in CLI help

Links

Launchpad bug: https://bugs.launchpad.net/juju/+bug/2073741

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

9 similar comments
@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@jujubot
Copy link
Collaborator

jujubot commented Sep 11, 2024

Thanks for opening a pull request! Please follow the instructions here to ensure your pull request is ready for review. Then, a maintainer will review your patch.

@hpidcock @anvial

@hpidcock hpidcock added the 3.5 label Sep 11, 2024
@hpidcock
Copy link
Member

@ca-scribner is this ready for review?

@ca-scribner
Copy link
Contributor Author

No sorry, I've got a suggestion from @wallyworld I'll be putting in this week. I'm following up with @wallyworld once its ready

@ca-scribner ca-scribner force-pushed the lp2073741-block-users-from-registering-over-their-current-controller branch from c5ed115 to b8b64c9 Compare September 24, 2024 20:26
Previously, users could do the following:

On computer 1:
```
juju add-user u1
juju add-user u2
````

On computer 2:
```
juju register TOKEN_FROM_u1
>> works
juju register TOKEN_FROM_u2 --replace
>> partially replaces the existing controller, but then fails to listModels
>> on a permission error because its macaroon chain has a mix of u1 and u2 credentials
```

A similar example with more explanation is in[lp2073741]
(https://bugs.launchpad.net/juju/+bug/2073741?comments=all).

This was caused by the client chaining macaroons for both user1 and user2 during the API calls,
leading to permission errors.  The `--replace` flag was implemented to swap users and does not
cover this case.

This commit prevents the above situation by:
* blocking users from `--replace`ing an existing controller they're logged into.  Instead, the users
  is prompted with an error and instructions for resolution.
* avoiding invaliding the user's registration token in some cases by adding validation to detect
  controller collisions before using the token.  This is done through updating
  `ensureNotKnownEndpoint()` to apply its checks to all address types.  Prior to this commit,
  register would attempt to catch duplicate controllers by comparing the new controller's address
  to all known controllers, but this check was only applied for CLI calls made with a "public
  host" (a host provided as a URL or IP in the `juju register URL` call).  This check was not
  applied to a controller defined by a base64 token. The present commit updates this check to apply
  to both address types

As a driveby, this commit also:
* refactors when we ask the user for a new password.  Previously, we asked for a new password prior
  to doing controller collision checks, resulting in users entering passwords unnecessarily
* fixes a mistake in the error message provided on controller collision during
  `ensureNotKnownEndpoint`.  Previously, this message instructed the user to generate a new token
  prior to trying again, but this is unnecessary as we haven't yet used/invalidated the existing
  token
@ca-scribner ca-scribner force-pushed the lp2073741-block-users-from-registering-over-their-current-controller branch from b8b64c9 to 3eba8be Compare September 26, 2024 16:02
@ca-scribner ca-scribner marked this pull request as ready for review September 26, 2024 16:02
@@ -794,6 +815,51 @@ func genAlreadyRegisteredError(controller, user string) error {
return errors.New(buf.String())
}

var alreadyRegisteredMessageTokenStillValidT = template.Must(template.New("").Parse(`
This controller has already been registered on this client as "{{.ControllerName}}".
To login user "{{.UserName}}" run 'juju login -u {{.UserName}} -c {{.ControllerName}}'.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing wording, but

"To login as user ..."

here and above etc

}
return errors.Trace(err)
}
// TODO: Is this check necessary? Can AccountDetails successfully return without setting .User?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't we already does this check in the ensureNotKnownEndpoint method?

	// Check if we know the username for this controller
	accountDetails, err := store.AccountDetails(existingName)
	if err != nil && !errors.IsNotFound(err) {
		return errors.Trace(err)
	}

	if accountDetails != nil {
		return genAlreadyRegisteredTokenStillValidError(existingName, accountDetails.User)
	}

The user may have been prompted for a different controller name to use, but the underlying associated between controller and user (based on ip address match) would have been checked already right? If there is a need for this same check in 2 different places, it seems the existing logic might be a bit convoluted and would benefit from a little extra refactoring. ie can we gather all the inputs needed for the logic up front; am i logged in, does the ip address exist already, is the controller name in the token matching something locally etc. Then the logic can be written a bit cleaner perhaps.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check here is similar to the one in ensureNotKnownEndpoint, but we have more information now and can do a more robust check. ensureNotKnownEndpoint compared by address to decide if we already know that controller (which could change over time), whereas here we compare UUID. So this check is (slightly) wider than the previous one.

The need for two checks comes from how we cannot get the controller UUID unless we log into the controller, and that requires burning the user's registration token. So we can't collapse the two checks into one and preserve the user's token on most collisions.

@@ -435,6 +443,21 @@ func (c *registerCommand) updateController(
if !c.replace || controllerName != name {
return genAlreadyRegisteredError(name, accountDetails.User)
}

// We are replacing the current controller - reject the request if this client is logged into that controller
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - use "." at the end of comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants