예제 #1
0
        // Returns a valid session or throws
        internal static Session LoginWithOob(string username,
                                             string password,
                                             int keyIterationCount,
                                             Dictionary <string, string> parameters,
                                             ClientInfo clientInfo,
                                             IUi ui,
                                             RestClient rest)
        {
            var answer = ApproveOob(username, parameters, ui, rest);

            if (answer == OobResult.Cancel)
            {
                throw new CanceledMultiFactorException("Out of band step is canceled by the user");
            }

            var extraParameters = new Dictionary <string, object>(1);

            if (answer.WaitForOutOfBand)
            {
                extraParameters["outofbandrequest"] = 1;
            }
            else
            {
                extraParameters["otp"] = answer.Passcode;
            }

            Session session;

            for (;;)
            {
                // In case of the OOB auth the server doesn't respond instantly. This works more like a long poll.
                // The server times out in about 10 seconds so there's no need to back off.
                var response = PerformSingleLoginRequest(username,
                                                         password,
                                                         keyIterationCount,
                                                         extraParameters,
                                                         clientInfo,
                                                         rest);

                session = ExtractSessionFromLoginResponse(response, keyIterationCount, clientInfo);
                if (session != null)
                {
                    break;
                }

                if (GetOptionalErrorAttribute(response, "cause") != "outofbandrequired")
                {
                    throw MakeLoginError(response);
                }

                // Retry
                extraParameters["outofbandretry"]   = "1";
                extraParameters["outofbandretryid"] = GetErrorAttribute(response, "retryid");
            }

            if (answer.RememberMe)
            {
                MarkDeviceAsTrusted(session, clientInfo, rest);
            }

            return(session);
        }
예제 #2
0
        //
        // Internal
        //

        internal static Session Login(string username, string password, ClientInfo clientInfo, IUi ui, RestClient rest)
        {
            // 1. First we need to request PBKDF2 key iteration count.
            //
            // We no longer request the iteration count from the server in a separate request because it
            // started to fail in weird ways. It seems there's a special combination or the UA and cookies
            // that returns the correct result. And that is not 100% reliable. After two or three attempts
            // it starts to fail again with an incorrect result.
            //
            // So we just went back a few years to the original way LastPass used to handle the iterations.
            // Namely, submit the default value and if it fails, the error would contain the correct value:
            // <response><error iterations="5000" /></response>
            var keyIterationCount = 100100;

            XDocument response = null;
            Session   session  = null;

            for (var i = 0; i < 2; i++)
            {
                // 2. Knowing the iterations count we can hash the password and log in.
                //    One the first attempt simply with the username and password.
                response = PerformSingleLoginRequest(username,
                                                     password,
                                                     keyIterationCount,
                                                     new Dictionary <string, object>(),
                                                     clientInfo,
                                                     rest);
                session = ExtractSessionFromLoginResponse(response, keyIterationCount, clientInfo);
                if (session != null)
                {
                    return(session);
                }

                // It's possible for the request above to come back with the correct iteration count.
                // In this case we have to parse and repeat.
                var correctIterationCount = GetOptionalErrorAttribute(response, "iterations");
                if (correctIterationCount == null)
                {
                    break;
                }

                if (!int.TryParse(correctIterationCount, out keyIterationCount))
                {
                    throw new InternalErrorException($"Failed to parse the iteration count, expected an integer value '{correctIterationCount}'");
                }
            }

            // 3. The simple login failed. This is usually due to some error, invalid credentials or
            //    a multifactor authentication being enabled.
            var cause = GetOptionalErrorAttribute(response, "cause");

            if (cause == null)
            {
                throw MakeLoginError(response);
            }

            // 3.1. One-time-password is required
            if (KnownOtpMethods.TryGetValue(cause, out var otpMethod))
            {
                session = LoginWithOtp(username,
                                       password,
                                       keyIterationCount,
                                       otpMethod,
                                       clientInfo,
                                       ui,
                                       rest);
            }

            // 3.2. Some out-of-bound authentication is enabled. This does not require any
            //      additional input from the user.
            else if (cause == "outofbandrequired")
            {
                session = LoginWithOob(username,
                                       password,
                                       keyIterationCount,
                                       GetAllErrorAttributes(response),
                                       clientInfo,
                                       ui,
                                       rest);
            }

            // Nothing worked
            if (session == null)
            {
                throw MakeLoginError(response);
            }

            return(session);
        }
예제 #3
0
        //
        // Internal
        //

        internal static Session Login(string username, string password, ClientInfo clientInfo, IUi ui, RestClient rest)
        {
            // 1. First we need to request PBKDF2 key iteration count.
            var keyIterationCount = RequestIterationCount(username, rest);

            // 2. Knowing the iterations count we can hash the password and log in.
            //    One the first attempt simply with the username and password.
            var response = PerformSingleLoginRequest(username,
                                                     password,
                                                     keyIterationCount,
                                                     new Dictionary <string, object>(),
                                                     clientInfo,
                                                     rest);
            var session = ExtractSessionFromLoginResponse(response, keyIterationCount, clientInfo);

            if (session != null)
            {
                return(session);
            }

            // 3. The simple login failed. This is usually due to some error, invalid credentials or
            //    a multifactor authentication being enabled.
            var cause = GetOptionalErrorAttribute(response, "cause");

            if (cause == null)
            {
                throw MakeLoginError(response);
            }

            // 3.1. One-time-password is required
            if (KnownOtpMethods.TryGetValue(cause, out var otpMethod))
            {
                session = LoginWithOtp(username,
                                       password,
                                       keyIterationCount,
                                       otpMethod,
                                       clientInfo,
                                       ui,
                                       rest);
            }

            // 3.2. Some out-of-bound authentication is enabled. This does not require any
            //      additional input from the user.
            else if (cause == "outofbandrequired")
            {
                session = LoginWithOob(username,
                                       password,
                                       keyIterationCount,
                                       GetAllErrorAttributes(response),
                                       clientInfo,
                                       ui,
                                       rest);
            }

            // Nothing worked
            if (session == null)
            {
                throw MakeLoginError(response);
            }

            return(session);
        }