Exemplo n.º 1
0
func (c *registerCommand) Run(ctx *cmd.Context) error {

	store := modelcmd.QualifyingClientStore{c.store}
	registrationParams, err := c.getParameters(ctx, store)
	if err != nil {
		return errors.Trace(err)
	}
	_, err = store.ControllerByName(registrationParams.controllerName)
	if err == nil {
		return errors.AlreadyExistsf("controller %q", registrationParams.controllerName)
	} else if !errors.IsNotFound(err) {
		return errors.Trace(err)
	}

	// During registration we must set a new password. This has to be done
	// atomically with the clearing of the secret key.
	payloadBytes, err := json.Marshal(params.SecretKeyLoginRequestPayload{
		registrationParams.newPassword,
	})
	if err != nil {
		return errors.Trace(err)
	}

	// Make the registration call. If this is successful, the client's
	// cookie jar will be populated with a macaroon that may be used
	// to log in below without the user having to type in the password
	// again.
	req := params.SecretKeyLoginRequest{
		Nonce: registrationParams.nonce[:],
		User:  registrationParams.userTag.String(),
		PayloadCiphertext: secretbox.Seal(
			nil, payloadBytes,
			&registrationParams.nonce,
			&registrationParams.key,
		),
	}
	resp, err := c.secretKeyLogin(registrationParams.controllerAddrs, req)
	if err != nil {
		return errors.Trace(err)
	}

	// Decrypt the response to authenticate the controller and
	// obtain its CA certificate.
	if len(resp.Nonce) != len(registrationParams.nonce) {
		return errors.NotValidf("response nonce")
	}
	var respNonce [24]byte
	copy(respNonce[:], resp.Nonce)
	payloadBytes, ok := secretbox.Open(nil, resp.PayloadCiphertext, &respNonce, &registrationParams.key)
	if !ok {
		return errors.NotValidf("response payload")
	}
	var responsePayload params.SecretKeyLoginResponsePayload
	if err := json.Unmarshal(payloadBytes, &responsePayload); err != nil {
		return errors.Annotate(err, "unmarshalling response payload")
	}

	// Store the controller and account details.
	controllerDetails := jujuclient.ControllerDetails{
		APIEndpoints:   registrationParams.controllerAddrs,
		ControllerUUID: responsePayload.ControllerUUID,
		CACert:         responsePayload.CACert,
	}
	if err := store.AddController(registrationParams.controllerName, controllerDetails); err != nil {
		return errors.Trace(err)
	}
	accountDetails := jujuclient.AccountDetails{
		User:            registrationParams.userTag.Canonical(),
		LastKnownAccess: string(permission.LoginAccess),
	}
	if err := store.UpdateAccount(registrationParams.controllerName, accountDetails); err != nil {
		return errors.Trace(err)
	}

	// Log into the controller to verify the credentials, and
	// list the models available.
	models, err := c.listModelsFunc(store, registrationParams.controllerName, accountDetails.User)
	if err != nil {
		return errors.Trace(err)
	}
	for _, model := range models {
		owner := names.NewUserTag(model.Owner)
		if err := store.UpdateModel(
			registrationParams.controllerName,
			jujuclient.JoinOwnerModelName(owner, model.Name),
			jujuclient.ModelDetails{model.UUID},
		); err != nil {
			return errors.Annotate(err, "storing model details")
		}
	}
	if err := store.SetCurrentController(registrationParams.controllerName); err != nil {
		return errors.Trace(err)
	}

	fmt.Fprintf(
		ctx.Stderr, "\nWelcome, %s. You are now logged into %q.\n",
		registrationParams.userTag.Id(), registrationParams.controllerName,
	)
	return c.maybeSetCurrentModel(ctx, store, registrationParams.controllerName, accountDetails.User, models)
}