Esempio n. 1
0
func (st *State) loginV1(tag, password, nonce string) error {
	var result struct {
		// TODO (cmars): remove once we can drop 1.18 login compatibility
		params.LoginResult

		params.LoginResultV1
	}
	err := st.APICall("Admin", 1, "", "Login", &params.LoginRequestCompat{
		LoginRequest: params.LoginRequest{
			AuthTag:     tag,
			Credentials: password,
			Nonce:       nonce,
		},
		// TODO (cmars): remove once we can drop 1.18 login compatibility
		Creds: params.Creds{
			AuthTag:  tag,
			Password: password,
			Nonce:    nonce,
		},
	}, &result)
	if err != nil {
		return err
	}

	// We've either logged into an Admin v1 facade, or a pre-facade (1.18) API
	// server.  The JSON field names between the structures are disjoint, so only
	// one should have an environ tag set.

	var environTag string
	var serverTag string
	var servers [][]network.HostPort
	var facades []params.FacadeVersions
	// For quite old servers, it is possible that they don't send down
	// the environTag.
	if result.LoginResult.EnvironTag != "" {
		environTag = result.LoginResult.EnvironTag
		// If the server doesn't support login v1, it doesn't support
		// multiple environments, so don't store a server tag.
		servers = params.NetworkHostsPorts(result.LoginResult.Servers)
		facades = result.LoginResult.Facades
	} else if result.LoginResultV1.EnvironTag != "" {
		environTag = result.LoginResultV1.EnvironTag
		serverTag = result.LoginResultV1.ServerTag
		servers = params.NetworkHostsPorts(result.LoginResultV1.Servers)
		facades = result.LoginResultV1.Facades
	}

	err = st.setLoginResult(tag, environTag, serverTag, servers, facades)
	if err != nil {
		return err
	}
	return nil
}
Esempio n. 2
0
File: state.go Progetto: makyo/juju
func (st *state) loginForVersion(tag names.Tag, password, nonce string, macaroons []macaroon.Slice, vers int) error {
	var result params.LoginResultV1
	request := &params.LoginRequest{
		AuthTag:     tagToString(tag),
		Credentials: password,
		Nonce:       nonce,
		Macaroons:   macaroons,
	}
	if tag == nil {
		// Add any macaroons from the cookie jar that might work for
		// authenticating the login request.
		request.Macaroons = append(request.Macaroons,
			httpbakery.MacaroonsForURL(st.bakeryClient.Client.Jar, st.cookieURL)...,
		)
	}
	err := st.APICall("Admin", vers, "", "Login", request, &result)
	if err != nil {
		return errors.Trace(err)
	}
	if result.DischargeRequired != nil {
		// The result contains a discharge-required
		// macaroon. We discharge it and retry
		// the login request with the original macaroon
		// and its discharges.
		if result.DischargeRequiredReason == "" {
			result.DischargeRequiredReason = "no reason given for discharge requirement"
		}
		if err := st.bakeryClient.HandleError(st.cookieURL, &httpbakery.Error{
			Message: result.DischargeRequiredReason,
			Code:    httpbakery.ErrDischargeRequired,
			Info: &httpbakery.ErrorInfo{
				Macaroon:     result.DischargeRequired,
				MacaroonPath: "/",
			},
		}); err != nil {
			return errors.Trace(err)
		}
		// Add the macaroons that have been saved by HandleError to our login request.
		request.Macaroons = httpbakery.MacaroonsForURL(st.bakeryClient.Client.Jar, st.cookieURL)
		result = params.LoginResultV1{} // zero result
		err = st.APICall("Admin", vers, "", "Login", request, &result)
		if err != nil {
			return errors.Trace(err)
		}
		if result.DischargeRequired != nil {
			return errors.Errorf("login with discharged macaroons failed: %s", result.DischargeRequiredReason)
		}
	}

	servers := params.NetworkHostsPorts(result.Servers)
	err = st.setLoginResult(tag, result.ModelTag, result.ControllerTag, servers, result.Facades)
	if err != nil {
		return errors.Trace(err)
	}
	st.serverVersion, err = version.Parse(result.ServerVersion)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}
Esempio n. 3
0
func (st *State) loginV0(tag, password, nonce string) error {
	var result params.LoginResult
	err := st.APICall("Admin", 0, "", "Login", &params.Creds{
		AuthTag:  tag,
		Password: password,
		Nonce:    nonce,
	}, &result)
	if err != nil {
		return err
	}
	servers := params.NetworkHostsPorts(result.Servers)
	// Don't set a server tag.
	if err = st.setLoginResult(tag, result.EnvironTag, "", servers, result.Facades); err != nil {
		return err
	}
	return nil
}
Esempio n. 4
0
func (st *State) loginV2(tag, password, nonce string) error {
	var result params.LoginResultV1
	request := &params.LoginRequest{
		AuthTag:     tag,
		Credentials: password,
		Nonce:       nonce,
	}
	err := st.APICall("Admin", 2, "", "Login", request, &result)
	if err != nil {
		// If the server complains about an empty tag it may be that we are
		// talking to an older server version that does not understand facades and
		// expects a params.Creds request instead of a params.LoginRequest. We
		// return a CodNotImplemented error to force login down to V1, which
		// supports older server logins. This may mask an actual empty tag in
		// params.LoginRequest, but that would be picked up in loginV1. V1 will
		// also produce a warning that we are ignoring an invalid API, so we do not
		// need to add one here.
		if err.Error() == `"" is not a valid tag` {
			return &params.Error{
				Message: err.Error(),
				Code:    params.CodeNotImplemented,
			}
		}
		return errors.Trace(err)
	}
	servers := params.NetworkHostsPorts(result.Servers)
	err = st.setLoginResult(tag, result.EnvironTag, result.ServerTag, servers, result.Facades)
	if err != nil {
		return errors.Trace(err)
	}
	st.serverVersion, err = version.Parse(result.ServerVersion)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}
Esempio n. 5
0
func (st *state) loginV2(tag names.Tag, password, nonce string) error {
	var result params.LoginResultV1
	request := &params.LoginRequest{
		AuthTag:     tagToString(tag),
		Credentials: password,
		Nonce:       nonce,
	}
	if tag == nil {
		// Add any macaroons that might work for authenticating the login request.
		request.Macaroons = httpbakery.MacaroonsForURL(st.bakeryClient.Client.Jar, st.cookieURL)
	}
	err := st.APICall("Admin", 2, "", "Login", request, &result)
	if err != nil {
		// If the server complains about an empty tag it may be that we are
		// talking to an older server version that does not understand facades and
		// expects a params.Creds request instead of a params.LoginRequest. We
		// return a CodNotImplemented error to force login down to V1, which
		// supports older server logins. This may mask an actual empty tag in
		// params.LoginRequest, but that would be picked up in loginV1. V1 will
		// also produce a warning that we are ignoring an invalid API, so we do not
		// need to add one here.
		if err.Error() == `"" is not a valid tag` {
			return &params.Error{
				Message: err.Error(),
				Code:    params.CodeNotImplemented,
			}
		}
		return errors.Trace(err)
	}
	if result.DischargeRequired != nil {
		// The result contains a discharge-required
		// macaroon. We discharge it and retry
		// the login request with the original macaroon
		// and its discharges.
		if result.DischargeRequiredReason == "" {
			result.DischargeRequiredReason = "no reason given for discharge requirement"
		}
		if err := st.bakeryClient.HandleError(st.cookieURL, &httpbakery.Error{
			Message: result.DischargeRequiredReason,
			Code:    httpbakery.ErrDischargeRequired,
			Info: &httpbakery.ErrorInfo{
				Macaroon:     result.DischargeRequired,
				MacaroonPath: "/",
			},
		}); err != nil {
			return errors.Trace(err)
		}
		// Add the macaroons that have been saved by HandleError to our login request.
		request.Macaroons = httpbakery.MacaroonsForURL(st.bakeryClient.Client.Jar, st.cookieURL)
		result = params.LoginResultV1{} // zero result
		err = st.APICall("Admin", 2, "", "Login", request, &result)
		if err != nil {
			return errors.Trace(err)
		}
		if result.DischargeRequired != nil {
			return errors.Errorf("login with discharged macaroons failed: %s", result.DischargeRequiredReason)
		}
	}

	servers := params.NetworkHostsPorts(result.Servers)
	err = st.setLoginResult(tag, result.EnvironTag, result.ServerTag, servers, result.Facades)
	if err != nil {
		return errors.Trace(err)
	}
	st.serverVersion, err = version.Parse(result.ServerVersion)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}