Example #1
0
        protected void Button1_Click(object sender, EventArgs e)
        {
            PfAuthParams pfAuthParams = new PfAuthParams();

            pfAuthParams.Phone        = txtPhone.Text;
            pfAuthParams.Mode         = pf_auth.MODE_SMS_ONE_WAY_OTP;
            pfAuthParams.SmsText      = "Digite o código <$otp$> para ter acesso ao sistema.";
            pfAuthParams.CertFilePath = Server.MapPath(".//pf//certs//cert_key.p12");

            string otp;
            int    callStatus, errorId;

            // o parâmetro "otp" contém a chave de acesso gerada pelo sistema e enviada para o telefone destino
            bool res = pf_auth.pf_authenticate(pfAuthParams, out otp, out callStatus, out errorId);

            // o código de status 'callStatus == 20' indica que o SMS foi enviado com sucesso
            if (callStatus == 20)
            {
                // guardar o código no SessionState para validar no próximo campo
                Session["otp"] = otp;
                Label1.Text    = "SMS enviado com sucesso!";
            }
            else
            {
                Label1.Text = "SMS não enviado - código de status: " + callStatus.ToString();
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            if (txtUsername.Text != "test" || txtPassword.Text != "test")
            {
                MessageBox.Show("Intial user credentials invalid");
                return;
            }

            PfAuthParams pfAuthParams = new PfAuthParams();

            pfAuthParams.Username = txtUsername.Text;
            pfAuthParams.Phone    = "8622664878";
            pfAuthParams.Mode     = pf_auth.MODE_SMS_ONE_WAY_OTP;

            pfAuthParams.CertFilePath = System.IO.Directory.GetCurrentDirectory() + "\\cert_key.p12";

            if (pf_auth.pf_authenticate(pfAuthParams, out otp, out status, out error))
            {
                MessageBox.Show("User must enter " + otp + " to continue!");
                groupBox1.Enabled = false;
                groupBox2.Enabled = true;
            }
            else
            {
                MessageBox.Show("Status: " + status + " Error: " + error);
                otp    = String.Empty;
                status = 0;
                error  = 0;
            }
        }
        public ActionResult Login(string alias, string phone)
        {
            // Add call details from the user database.
            PfAuthParams pfAuthParams = new PfAuthParams();
            pfAuthParams.Username = alias + "@sqlninja.onmicrosoft.com";
            pfAuthParams.Phone = phone;
            pfAuthParams.Mode = pf_auth.MODE_STANDARD;

            // Specify a client certificate
            // NOTE: This file contains the private key for the client
            // certificate. It must be stored with appropriate file
            // permissions.
            pfAuthParams.CertFilePath = System.Web.HttpContext.Current.Server.MapPath("~/Libraries/Cert/cert_key.p12");

            // Perform phone-based authentication
            int callStatus;
            int errorId;

            if (pf_auth.pf_authenticate(pfAuthParams, out callStatus, out errorId))
            {
                System.Diagnostics.Debug.WriteLine("Multi-Factor Authentication succeeded.");
                ViewBag.Message = "";
                return View("CustomerTrendMain");
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Multi-Factor Authentication failed.");
                ViewBag.Message = "Multi-Factor Authentication failed.";
                return View("Index");
            }
        }
Example #4
0
    //
    // create_authenticate_message: generates an authenticate message to be sent
    // 	to the PhoneFactor backend.
    //
    // Return value:
    //     a complete authentication xml message ready to be sent to the PhoneFactor backend
    //
    private static string create_authenticate_message(
    PfAuthParams pfAuthParams,
    bool asynchronous)
    {
        bool sms = pfAuthParams.Mode == MODE_SMS_TWO_WAY_OTP || pfAuthParams.Mode == MODE_SMS_TWO_WAY_OTP_PLUS_PIN
          || pfAuthParams.Mode == MODE_SMS_ONE_WAY_OTP || pfAuthParams.Mode == MODE_SMS_ONE_WAY_OTP_PLUS_PIN;
        bool two_way = pfAuthParams.Mode == MODE_SMS_TWO_WAY_OTP || pfAuthParams.Mode == MODE_SMS_TWO_WAY_OTP_PLUS_PIN;
        bool otp = pfAuthParams.Mode == MODE_SMS_TWO_WAY_OTP || pfAuthParams.Mode == MODE_SMS_ONE_WAY_OTP;
        bool phone_app = pfAuthParams.Mode == MODE_PHONE_APP_STANDARD || pfAuthParams.Mode == MODE_PHONE_APP_PIN;
        bool phone_app_pin = pfAuthParams.Mode == MODE_PHONE_APP_PIN;

        XmlDocument doc = new XmlDocument();

        // start message
        // <pfpMessage></pfpMessage>
        XmlElement root = doc.CreateElement("pfpMessage");
        root.SetAttribute("version", "1.5");
        doc.AppendChild(root);

        // message header
        // <header></header>
        XmlElement header = doc.CreateElement("header");
        root.AppendChild(header);
        XmlElement source = doc.CreateElement("source");
        header.AppendChild(source);
        XmlElement component = doc.CreateElement("component");
        component.SetAttribute("type", "pfsdk");
        source.AppendChild(component);
        XmlElement element = doc.CreateElement("host");
        element.SetAttribute("ip", pfAuthParams.IpAddress);
        element.SetAttribute("hostname", pfAuthParams.Hostname);
        component.AppendChild(element);

        // request
        // <request></request>
        XmlElement request = doc.CreateElement("request");
        Random random = new Random();
        if (pfAuthParams.RequestId == null || pfAuthParams.RequestId.Length == 0) pfAuthParams.RequestId = random.Next(10000).ToString();
        request.SetAttribute("request-id", pfAuthParams.RequestId);
        request.SetAttribute("language", pfAuthParams.Language);
        request.SetAttribute("async", asynchronous ? "1" : "0");
        request.SetAttribute("response-url", pfAuthParams.ResponseUrl);
        root.AppendChild(request);
        XmlElement auth_request = doc.CreateElement("authenticationRequest");
        if (sms) auth_request.SetAttribute("mode", "sms");
        if (phone_app) auth_request.SetAttribute("mode", "phoneApp");
        request.AppendChild(auth_request);
        XmlElement customer = doc.CreateElement("customer");
        auth_request.AppendChild(customer);
        element = doc.CreateElement("licenseKey");
        element.InnerText = LICENSE_KEY;
        customer.AppendChild(element);
        element = doc.CreateElement("groupKey");
        element.InnerText = GROUP_KEY;
        customer.AppendChild(element);
        element = doc.CreateElement("countryCode");
        element.InnerText = pfAuthParams.CountryCode;
        auth_request.AppendChild(element);
        element = doc.CreateElement("authenticationType");
        element.InnerText = "pfsdk";
        auth_request.AppendChild(element);
        element = doc.CreateElement("username");
        element.InnerText = pfAuthParams.Username;
        auth_request.AppendChild(element);
        element = doc.CreateElement("phonenumber");
        element.SetAttribute("userCanChangePhone", "no");
        element.InnerText = pfAuthParams.Phone;
        if (pfAuthParams.Extension != null && pfAuthParams.Extension.Length != 0)
        {
          element.SetAttribute("extension", pfAuthParams.Extension);
        }
        auth_request.AppendChild(element);
        element = doc.CreateElement("allowInternationalCalls");
        element.InnerText = pfAuthParams.AllowInternationalCalls ? "yes" : "no";
        auth_request.AppendChild(element);
        element = doc.CreateElement("applicationName");
        element.InnerText = pfAuthParams.ApplicationName;
        auth_request.AppendChild(element);

        XmlElement pin_info = doc.CreateElement("pinInfo");
        XmlElement pin_element = doc.CreateElement("pin");
        if (pfAuthParams.Mode == MODE_PIN || pfAuthParams.Mode == MODE_SMS_TWO_WAY_OTP_PLUS_PIN)
        {
          string pinFormat;
          string pinFormatted;
          if (pfAuthParams.Sha1PinHash.Length == 0)
          {
        pinFormat = "plainText";
        pinFormatted = pfAuthParams.Pin;
          }
          else
          {
        pinFormat = "sha1";
        pinFormatted = pfAuthParams.Sha1PinHash;
          }

          pin_element.SetAttribute("pinFormat", pinFormat);
          if (pfAuthParams.Sha1PinHash.Length != 0)
          {
        pin_element.SetAttribute("sha1Salt", pfAuthParams.Sha1Salt);
          }
          pin_element.SetAttribute("pinChangeRequired", "no");
          pin_element.InnerText = pinFormatted;
        }

        if (sms)
        {
          XmlElement sms_info = doc.CreateElement("smsInfo");
          sms_info.SetAttribute("direction", two_way ? "two-way" : "one-way");
          sms_info.SetAttribute("mode", otp ? "otp" : "otp-pin");
          element = doc.CreateElement("message");
          element.InnerText = pfAuthParams.SmsText;
          sms_info.AppendChild(element);
          if (pfAuthParams.Mode == MODE_SMS_TWO_WAY_OTP_PLUS_PIN) sms_info.AppendChild(pin_element);
          auth_request.AppendChild(sms_info);
          pin_info.SetAttribute("pinMode", MODE_STANDARD);
        }
        else if (phone_app)
        {
          XmlElement phone_app_auth_info = doc.CreateElement("phoneAppAuthInfo");
          phone_app_auth_info.SetAttribute("mode", phone_app_pin ? "pin" : "standard");
          XmlElement device_tokens = doc.CreateElement("deviceTokens");
          element = doc.CreateElement("deviceToken");
          if (pfAuthParams.NotificationType.Length > 0)
          {
        element.SetAttribute("notificationType", pfAuthParams.NotificationType);
          }
          element.InnerText = pfAuthParams.DeviceToken;
          device_tokens.AppendChild(element);
          phone_app_auth_info.AppendChild(device_tokens);
          element = doc.CreateElement("phoneAppAccountName");
          element.InnerText = pfAuthParams.AccountName;
          phone_app_auth_info.AppendChild(element);
          if (phone_app_pin)
          {
        element = doc.CreateElement("pin");
        element.SetAttribute("pinChangeRequired", "0");
        string pinFormat;
        string pinFormatted;
        if (pfAuthParams.Sha1PinHash.Length == 0)
        {
          pinFormat = "plainText";
          pinFormatted = pfAuthParams.Pin;
        }
        else
        {
          pinFormat = "sha1";
          pinFormatted = pfAuthParams.Sha1PinHash;
        }
        element.SetAttribute("pinFormat", pinFormat);
        if (pfAuthParams.Sha1PinHash.Length != 0)
        {
          element.SetAttribute("sha1Salt", pfAuthParams.Sha1Salt);
        }
        element.InnerText = pinFormatted;
        phone_app_auth_info.AppendChild(element);
          }
          XmlElement phone_app_messages = doc.CreateElement("phoneAppMessages");
          element = doc.CreateElement("message");
          element.SetAttribute("type", "authenticateButton");
          element.InnerText = "Authenticate";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "authenticationDenied");
          element.InnerText = "PhoneFactor authentication denied.";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "authenticationSuccessful");
          element.InnerText = "You have successfully authenticated using PhoneFactor.";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "cancelButton");
          element.InnerText = "Cancel";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "closeButton");
          element.InnerText = "Close";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "denyAndReportFraudButton");
          element.InnerText = "Deny and Report Fraud";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "denyButton");
          element.InnerText = "Deny";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "fraudConfirmationNoBlock");
          element.InnerText = "Your company's fraud response team will be notified.";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "fraudConfirmationWithBlock");
          element.InnerText = "Your account will be blocked preventing further authentications and the company's fraud response team will be notified.";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "fraudReportedNoBlock");
          element.InnerText = "Fraud reported.";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "fraudReportedWithBlock");
          element.InnerText = "Fraud reported and account blocked.";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "notification");
          element.InnerText = "You have received a PhoneFactor authentication request.";
          phone_app_messages.AppendChild(element);
          element = doc.CreateElement("message");
          element.SetAttribute("type", "reportFraudButton");
          element.InnerText = "Report Fraud";
          phone_app_messages.AppendChild(element);

          if (pfAuthParams.Mode == MODE_PHONE_APP_STANDARD)
          {
        element = doc.CreateElement("message");
        element.SetAttribute("type", "standard");
        element.InnerText = "Tap Authenticate to complete your authentication.";
        phone_app_messages.AppendChild(element);
          }
          else
          {
        element = doc.CreateElement("message");
        element.SetAttribute("type", "confirmPinField");
        element.InnerText = "Confirm PIN";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "newPinField");
        element.InnerText = "New PIN";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pin");
        element.InnerText = "Enter your PIN and tap Authenticate to complete your authentication.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinAllSameDigits");
        element.InnerText = "Your PIN cannot contain 3 or more repeating digits.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinExpired");
        element.InnerText = "Your PIN has expired. Please enter a new PIN to complete your authentication.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinField");
        element.InnerText = "PIN";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinHistoryDuplicate");
        element.InnerText = "Your PIN cannot be the same as one of your recently used PINs. Please choose a different PIN.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinLength");
        element.InnerText = "Your PIN must be a minimum of 4 digits.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinMismatch");
        element.InnerText = "New PIN and Confirm PIN must match.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinRetry");
        element.InnerText = "Incorrect PIN. Please try again.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinSequentialDigits");
        element.InnerText = "Your PIN cannot contain 3 or more sequential digits ascending or descending.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "pinSubsetOfPhone");
        element.InnerText = "Your PIN cannot contain a 4 digit subset of your phone number or backup phone number.";
        phone_app_messages.AppendChild(element);
        element = doc.CreateElement("message");
        element.SetAttribute("type", "saveButton");
        element.InnerText = "Save";
        phone_app_messages.AppendChild(element);
          }
          phone_app_auth_info.AppendChild(phone_app_messages);
          auth_request.AppendChild(phone_app_auth_info);
        }
        else
        {
          pin_info.SetAttribute("pinMode", pfAuthParams.Mode);
          if (pfAuthParams.Mode == MODE_PIN) pin_info.AppendChild(pin_element);
          element = doc.CreateElement("userCanChangePin");
          element.InnerText = "no";
          pin_info.AppendChild(element);
        }
        auth_request.AppendChild(pin_info);

        return doc.InnerXml;
    }
Example #5
0
    // Deprecated - for backward compatibility only
    public static bool pf_authenticate_async(
    string username,
    string phone,
    string country_code,
    bool allow_int_calls,
    string sha1_pin_hash,
    string sha1_salt,
    string hostname,
    string ip,
    string cert_file_path,
    string response_url,
    out int call_status,
    out int error_id)
    {
        PfAuthParams pfAuthParams = new PfAuthParams();
        pfAuthParams.Username = username;
        pfAuthParams.CountryCode = country_code;
        pfAuthParams.Phone = phone;
        pfAuthParams.AllowInternationalCalls = allow_int_calls;
        pfAuthParams.Mode = MODE_PIN;
        pfAuthParams.Sha1PinHash = sha1_pin_hash;
        pfAuthParams.Sha1Salt = sha1_salt;
        pfAuthParams.Hostname = hostname;
        pfAuthParams.IpAddress = ip;
        pfAuthParams.CertFilePath = cert_file_path;
        pfAuthParams.ResponseUrl = response_url;

        return pf_authenticate_internal(
          pfAuthParams,
          true,
          out call_status,
          out error_id);
    }
Example #6
0
 public static bool pf_authenticate_async(
 PfAuthParams pfAuthParams,
 out int callStatus,
 out int errorId)
 {
     return pf_authenticate_internal(
       pfAuthParams,
       true,
       out callStatus,
       out errorId);
 }
Example #7
0
    // PIN Mode with clear text PIN.
    public static bool pf_authenticate(
    string username,
    string phone,
    string country_code,
    bool allow_int_calls,
    string pin,
    string hostname,
    string ip,
    string cert_file_path,
    out int call_status,
    out int error_id)
    {
        PfAuthParams pfAuthParams = new PfAuthParams();
        pfAuthParams.Username = username;
        pfAuthParams.CountryCode = country_code;
        pfAuthParams.Phone = phone;
        pfAuthParams.AllowInternationalCalls = allow_int_calls;
        pfAuthParams.Mode = MODE_PIN;
        pfAuthParams.Pin = pin;
        pfAuthParams.Hostname = hostname;
        pfAuthParams.IpAddress = ip;
        pfAuthParams.CertFilePath = cert_file_path;

        return pf_authenticate_internal(
          pfAuthParams,
          false,
          out call_status,
          out error_id);
    }
Example #8
0
 //
 // pf_authenticate, pf_authenticate_async: authenticates using PhoneFactor.
 //
 // Arguments:
 //     1) username: the username to be auth'd
 //     2) country_code: the country code to be used for the call.  defaults to 1.
 //     3) phone: the phone number to PhoneFactor authenticate
 //     4) extension: the extension to dial after the call is connected
 //     5) allow_int_calls: a boolean value that determines whether international
 //        calls should be allowed.  defaults to false.  note that this only needs to
 //        be set to true if the call you are making is international, and thus could
 //        cost you money.  see www.phonefactor.net for the PhoneFactor rate table
 //        that shows which calling zones will cost money and which are free.
 //     6) mode: specify whether to use "standard", "pin", "voiceprint",
 //        "sms_two_way_otp" or "sms_two_way_otp_plus_pin" mode
 //        standard: user presses #
 //        pin: user enters their pin and #
 //        voiceprint: user says their passphrase and their voice is matched
 //        sms_two_way_otp: user responds to text with OTP
 //        sms_two_way_otp_plus_pin: user responds to text with OTP + PIN
 //        phone_app_standard: user selects Authenticate in phone app
 //        phone_app_pin: user enters their pin and selects Authenticate in the phone app
 //     7) pin: PIN the user must enter during the call
 //     8) sha1_pin_hash: SHA1 encrypted PIN the user must enter during the call
 //     9) sha1_salt: SHA1 salt appended to PIN prior to encryption
 //   	 10) $application_name: Specify the appliation name to display on reports in the
 //         PhoneFactor Management Portal.
 //   	 11) $device_token: Specify the device token of the device to send the
 //             phone app notification to.
 //       12) $account_name: Specify the account name to display in the phone app.
 //     13) hostname: the hostname this authentication is being sent from.
 //           defaults to 'pfsdk-hostname'
 //     14) ip: the ip address this authentication is being sent from.
 //           defaults to '255.255.255.255'
 //     15) cert_file_path: the path and file name of the certificate file
 //     16) request_id: a string identifying the request that can be used to match
 //         the asynchronous response to the original request
 //     17) response_url: the URL that the final response for an asynchronous request
 //         should be sent to
 //     18) otp: One-time passcode (OTP) included in SMS text and returned for
 //         one-way SMS.
 //     19) call_status: an integer code returned representing the status of the
 //         phonecall.
 //     20) error_id: an integer code returned if the connection to the PhoneFactor
 //         backend failed.
 //
 // Return value:
 //     A boolean value representing whether the auth was successful or not.
 //     If true, then the call_status and error_id output arguments can safely be
 //     ignored.
 //
 // New implementations using class to pass parameters.
 public static bool pf_authenticate(
 PfAuthParams pfAuthParams,
 out string otp,
 out int callStatus,
 out int errorId)
 {
     return pf_authenticate_internal(
       pfAuthParams,
       false,
       out otp,
       out callStatus,
       out errorId);
 }
Example #9
0
    private static bool pf_authenticate_internal(
    PfAuthParams pfAuthParams,
    bool asynchronous,
    out string otp,
    out int call_status,
    out int error_id)
    {
        if (pfAuthParams.CountryCode.Length == 0) pfAuthParams.CountryCode = "1";
        if (pfAuthParams.Hostname.Length == 0) pfAuthParams.Hostname = "pfsdk-hostname";
        if (pfAuthParams.IpAddress.Length == 0) pfAuthParams.IpAddress = "255.255.255.255";
        pfAuthParams.Mode = pfAuthParams.Mode.ToLower();
        if (pfAuthParams.Mode != MODE_STANDARD && pfAuthParams.Mode != MODE_PIN && pfAuthParams.Mode != MODE_VOICEPRINT
          && pfAuthParams.Mode != MODE_SMS_TWO_WAY_OTP && pfAuthParams.Mode != MODE_SMS_TWO_WAY_OTP_PLUS_PIN
          && pfAuthParams.Mode != MODE_SMS_ONE_WAY_OTP && pfAuthParams.Mode != MODE_SMS_ONE_WAY_OTP_PLUS_PIN
          && pfAuthParams.Mode != MODE_PHONE_APP_STANDARD && pfAuthParams.Mode != MODE_PHONE_APP_PIN) pfAuthParams.Mode = MODE_STANDARD;

        otp = "";
        call_status = 0;
        error_id = 0;

        string auth_message = create_authenticate_message(pfAuthParams, asynchronous);

        int tries = 1;
        if (mMutex.WaitOne())
        {
          try { tries = mTargets.Count + 1; }
          finally { mMutex.ReleaseMutex(); }
        }
        for (int i = 0; i < tries; i++)
        {
          string response;
          if (send_message(mCurrentTarget, auth_message, pfAuthParams.CertFilePath, out response))
          {
        string request_id_out = "";
        bool authenticated = get_response_status(response, out request_id_out, out otp, out call_status, out error_id);
        return authenticated;
          }
          else
          {
        if (mMutex.WaitOne())
        {
          try
          {
            mTargets.Enqueue(mCurrentTarget);
            mCurrentTarget = mTargets.Dequeue().ToString();
          }
          finally { mMutex.ReleaseMutex(); }
        }
          }
        }
        return false;
    }
Example #10
0
 private static bool pf_authenticate_internal(
 PfAuthParams pfAuthParams,
 bool asynchronous,
 out int call_status,
 out int error_id)
 {
     string otp = "";
     return pf_authenticate_internal(pfAuthParams, asynchronous, out otp, out call_status, out error_id);
 }
        public async Task <ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                var user = await UserManager.FindAsync(model.Email, model.Password);

                if (user != null)
                {
                    //await UserManager.SignInAsync(user, model.RememberMe);
                    await SignInManager.SignInAsync(user, model.RememberMe, rememberBrowser : false);

                    // Variables to store MFA results
                    string otp        = "";
                    int    callStatus = 0;
                    int    errorId    = 0;

                    // Prepare the MFA Parameters
                    PfAuthParams pfAuthParams = new PfAuthParams();
                    pfAuthParams.CountryCode = user.CountryCode;
                    pfAuthParams.Phone       = user.Phone;
                    pfAuthParams.Pin         = user.PIN.ToString();

                    // Load the certificate
                    pfAuthParams.CertFilePath = System.Web.HttpContext.Current.Server.MapPath("~/pf/certs/cert_key.p12");

                    // Choose one of the below methods for authentication
                    pfAuthParams.Mode = pf_auth.MODE_STANDARD; // a phone call without a pin
                    //pfAuthParams.Mode = pf_auth.MODE_PIN; // pin
                    //pfAuthParams.Mode = pf_auth.MODE_VOICEPRINT; // voice print
                    //pfAuthParams.Mode = pf_auth.MODE_SMS_TWO_WAY_OTP; // sms him a one time password that he has to send back
                    //pfAuthParams.Mode = pf_auth.MODE_SMS_TWO_WAY_OTP_PLUS_PIN; // sms him a one time password that he has to send back + pin

                    // If using SMS, set the below according to the SMS mode
                    //pfAuthParams.SmsText = "<$otp$>\nReply with this one-time passcode to complete your authentication.";
                    //pfAuthParams.SmsText = "<$otp$>\nReply with this one-time passcode and your PIN to complete your authentication.";

                    // Call the MFA Provider
                    // the return value from the function is a boolean that is the result of
                    // the authentication.  Two out arguments are also returned.  The first is the
                    // result of the phonecall itself, the second is the result of the connection
                    // with the backend.  See call_results.txt for a list of call results
                    // and descriptions that correspond to value returned.
                    bool mfaResult = pf_auth.pf_authenticate(pfAuthParams, out otp, out callStatus, out errorId);

                    // If MFA succeeded
                    if (mfaResult == true)
                    {
                        return(RedirectToLocal(returnUrl));
                    }
                    else
                    {
                        ModelState.AddModelError("", "Multi-factor Authentication failed.");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "Invalid username or password.");
                }
            }

            // Сбои при входе не приводят к блокированию учетной записи
            // Чтобы ошибки при вводе пароля инициировали блокирование учетной записи, замените на shouldLockout: true
            var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout : true);

            switch (result)
            {
            case SignInStatus.Success:
                return(RedirectToLocal(returnUrl));

            case SignInStatus.LockedOut:
                return(View("Lockout"));

            case SignInStatus.RequiresVerification:
                return(RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }));

            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Неудачная попытка входа.");
                return(View(model));
            }
        }