func (st *state) loginForVersion(tag names.Tag, password, nonce string, macaroons []macaroon.Slice, vers int) error { var result params.LoginResultV1 request := ¶ms.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 }
func (st *state) loginV2(tag names.Tag, password, nonce string) error { var result params.LoginResultV1 request := ¶ms.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 ¶ms.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 }