binita
1 year ago
14 changed files with 608 additions and 34 deletions
-
68API/GoogleAuthenticatorAPI.cs
-
170API/Model/EncryptDecryptUtility.cs
-
15API/Model/GoogleAuthenticatorModel.cs
-
6Business/Account/AccountServices.cs
-
3Business/Account/IAccountServices.cs
-
8JMEAgentSystem/Scripts/Account/Login.js
-
2JMEAgentSystem/Scripts/Customer/CustomerRegistration.js
-
137JMEAgentSystem/WebPages/Account/Authenticate.aspx
-
64JMEAgentSystem/WebPages/Account/Authenticate.aspx.cs
-
80JMEAgentSystem/WebPages/Account/Authenticate.aspx.designer.cs
-
15JMEAgentSystem/WebPages/Account/Login.aspx.cs
-
11JMEAgentSystem/WebPages/CustomerRegistration/Manage.aspx
-
10Repository/DAO/Account/AccountRepo.cs
-
1Repository/DAO/Account/IAccountRepo.cs
@ -0,0 +1,68 @@ |
|||
using API.Model; |
|||
using Common.Utility; |
|||
using Google.Authenticator; |
|||
using System.Configuration; |
|||
using System.Web; |
|||
|
|||
namespace API |
|||
{ |
|||
public class GoogleAuthenticatorAPI |
|||
{ |
|||
protected TwoFactorAuthenticator _tfa = new TwoFactorAuthenticator(); |
|||
protected string _key = ReadWebConfig("2FAGoogle", ""); |
|||
protected string _keyForEncDec = ReadWebConfig("keyForEncryptionDecryption", ""); |
|||
|
|||
public GoogleAuthenticatorModel GenerateCodeAndImageURL(string userName) |
|||
{ |
|||
GoogleAuthenticatorModel _model = new GoogleAuthenticatorModel(); |
|||
string userUniqueKeyEncrypted = EncryptDecryptUtility.Encrypt(userName + _key, _keyForEncDec); |
|||
WriteSession("UserUniqueKey", userUniqueKeyEncrypted); |
|||
|
|||
var _googleSetupInfo = _tfa.GenerateSetupCode("JME REMIT", userName, userUniqueKeyEncrypted, 200, 200, true); |
|||
_model.SetupCode = _googleSetupInfo.ManualEntryKey; |
|||
_model.BarCodeImageUrl = _googleSetupInfo.QrCodeSetupImageUrl; |
|||
|
|||
return _model; |
|||
} |
|||
|
|||
public GoogleAuthenticatorModel GenerateCodeAndImageURL(string userName, string userUniqueKeyEncrypted) |
|||
{ |
|||
GoogleAuthenticatorModel _model = new GoogleAuthenticatorModel(); |
|||
|
|||
var _googleSetupInfo = _tfa.GenerateSetupCode("JME REMIT", userName, userUniqueKeyEncrypted, 200, 200, true); |
|||
_model.SetupCode = _googleSetupInfo.ManualEntryKey; |
|||
_model.BarCodeImageUrl = _googleSetupInfo.QrCodeSetupImageUrl; |
|||
_model.ManualEntryKey = _googleSetupInfo.ManualEntryKey; |
|||
|
|||
return _model; |
|||
} |
|||
|
|||
public DbResult Verify2FA(string otp, string userUniqueKey) |
|||
{ |
|||
DbResult _dbRes = new DbResult(); |
|||
if (string.IsNullOrEmpty(otp)) |
|||
{ |
|||
_dbRes.SetError("1", "OTP Code can not be blank!", null); |
|||
return _dbRes; |
|||
} |
|||
|
|||
bool isValid = _tfa.ValidateTwoFactorPIN(userUniqueKey, otp); |
|||
if (isValid) |
|||
_dbRes.SetError("0", "Two factor authentication verified successfully!", null); |
|||
else |
|||
_dbRes.SetError("1", "Please enter valid OTP!", null); |
|||
|
|||
return _dbRes; |
|||
} |
|||
|
|||
public static string ReadWebConfig(string key, string defValue) |
|||
{ |
|||
return (ConfigurationSettings.AppSettings[key] ?? defValue).ToString(); |
|||
} |
|||
|
|||
public static void WriteSession(string key, string value) |
|||
{ |
|||
HttpContext.Current.Session[key] = value; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,170 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Security.Cryptography; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace API.Model |
|||
{ |
|||
public class EncryptDecryptUtility |
|||
{ |
|||
protected static string saltValue = "K0r3@GM3"; |
|||
protected static string hashAlgorithm = "SHA1"; |
|||
protected static int passwordIterations = 5; |
|||
protected static string initVector = "P@s$w0rDGm3KoR3@"; |
|||
protected static int keySize = 256; |
|||
|
|||
/// <summary>
|
|||
/// Encrypts specified plaintext using Rijndael symmetric key algorithm
|
|||
/// and returns a base64-encoded result.
|
|||
/// </summary>
|
|||
/// <param name="plainText">Plain Text to Encrypt</param>
|
|||
/// <param name="passPhrase">Pass Phrase to use in Password Generation</param>
|
|||
/// <returns>Encrypted text encoded into Base 64 text format </returns>
|
|||
public static string Encrypt(string plainText, string passPhrase) |
|||
{ |
|||
// Convert strings into byte arrays.
|
|||
// Let us assume that strings only contain ASCII codes.
|
|||
// If strings include Unicode characters, use Unicode, UTF7, or UTF8
|
|||
// encoding.
|
|||
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); |
|||
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); |
|||
|
|||
// Convert our plaintext into a byte array.
|
|||
// Let us assume that plaintext contains UTF8-encoded characters.
|
|||
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); |
|||
|
|||
// First, we must create a password, from which the key will be derived.
|
|||
// This password will be generated from the specified passphrase and
|
|||
// salt value. The password will be created using the specified hash
|
|||
// algorithm. Password creation can be done in several iterations.
|
|||
var password = new PasswordDeriveBytes( |
|||
passPhrase, |
|||
saltValueBytes, |
|||
hashAlgorithm, |
|||
passwordIterations); |
|||
|
|||
// Use the password to generate pseudo-random bytes for the encryption
|
|||
// key. Specify the size of the key in bytes (instead of bits).
|
|||
#pragma warning disable 618, 612
|
|||
byte[] keyBytes = password.GetBytes(keySize / 8); |
|||
#pragma warning restore 618, 612
|
|||
|
|||
// Create uninitialized Rijndael encryption object.
|
|||
var symmetricKey = new RijndaelManaged(); |
|||
|
|||
// It is reasonable to set encryption mode to Cipher Block Chaining
|
|||
// (CBC). Use default options for other symmetric key parameters.
|
|||
symmetricKey.Mode = CipherMode.CBC; |
|||
|
|||
// Generate encryptor from the existing key bytes and initialization
|
|||
// vector. Key size will be defined based on the number of the key
|
|||
// bytes.
|
|||
ICryptoTransform encryptor = symmetricKey.CreateEncryptor( |
|||
keyBytes, |
|||
initVectorBytes); |
|||
|
|||
var memoryStream = new MemoryStream(); |
|||
|
|||
// Define memory stream which will be used to hold encrypted data.
|
|||
var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); |
|||
|
|||
// Start encrypting.
|
|||
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); |
|||
|
|||
// Finish encrypting.
|
|||
cryptoStream.FlushFinalBlock(); |
|||
|
|||
// Convert our encrypted data from a memory stream into a byte array.
|
|||
byte[] cipherTextBytes = memoryStream.ToArray(); |
|||
|
|||
// Close both streams.
|
|||
memoryStream.Close(); |
|||
cryptoStream.Close(); |
|||
|
|||
// Convert encrypted data into a base64-encoded string.
|
|||
string cipherText = Convert.ToBase64String(cipherTextBytes); |
|||
|
|||
// Return encrypted string.
|
|||
return cipherText; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Decrypts specified cipherText using Rijndael symmetric key algorithm
|
|||
/// and returns a plain text result.
|
|||
/// </summary>
|
|||
/// <param name="cipherText">Encryted Text</param>
|
|||
/// <param name="passPhrase">Pass Phrase used in Password Generation</param>
|
|||
/// <returns></returns>
|
|||
public static string Decrypt(string cipherText, string passPhrase) |
|||
{ |
|||
// Convert strings defining encryption key characteristics into byte
|
|||
// arrays. Let us assume that strings only contain ASCII codes.
|
|||
// If strings include Unicode characters, use Unicode, UTF7, or UTF8
|
|||
// encoding.
|
|||
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); |
|||
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); |
|||
|
|||
// Convert our ciphertext into a byte array.
|
|||
byte[] cipherTextBytes = Convert.FromBase64String(cipherText); |
|||
|
|||
// First, we must create a password, from which the key will be
|
|||
// derived. This password will be generated from the specified
|
|||
// passphrase and salt value. The password will be created using
|
|||
// the specified hash algorithm. Password creation can be done in
|
|||
// several iterations.
|
|||
var password = new PasswordDeriveBytes( |
|||
passPhrase, |
|||
saltValueBytes, |
|||
hashAlgorithm, |
|||
passwordIterations); |
|||
|
|||
// Use the password to generate pseudo-random bytes for the encryption
|
|||
// key. Specify the size of the key in bytes (instead of bits).
|
|||
#pragma warning disable 618, 612
|
|||
byte[] keyBytes = password.GetBytes(keySize / 8); |
|||
#pragma warning restore 618, 612
|
|||
|
|||
// Create uninitialized Rijndael encryption object.
|
|||
var symmetricKey = new RijndaelManaged(); |
|||
|
|||
// It is reasonable to set encryption mode to Cipher Block Chaining
|
|||
// (CBC). Use default options for other symmetric key parameters.
|
|||
symmetricKey.Mode = CipherMode.CBC; |
|||
|
|||
// Generate decryptor from the existing key bytes and initialization
|
|||
// vector. Key size will be defined based on the number of the key
|
|||
// bytes.
|
|||
ICryptoTransform decryptor = symmetricKey.CreateDecryptor( |
|||
keyBytes, |
|||
initVectorBytes); |
|||
|
|||
// Define memory stream which will be used to hold encrypted data.
|
|||
var memoryStream = new MemoryStream(cipherTextBytes); |
|||
|
|||
// Define cryptographic stream (always use Read mode for encryption).
|
|||
var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read); |
|||
|
|||
// Since at this point we don't know what the size of decrypted data
|
|||
// will be, allocate the buffer long enough to hold ciphertext;
|
|||
// plaintext is never longer than ciphertext.
|
|||
var plainTextBytes = new byte[cipherTextBytes.Length]; |
|||
|
|||
// Start decrypting.
|
|||
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); |
|||
|
|||
// Close both streams.
|
|||
memoryStream.Close(); |
|||
cryptoStream.Close(); |
|||
|
|||
// Convert decrypted data into a string.
|
|||
// Let us assume that the original plaintext string was UTF8-encoded.
|
|||
string plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); |
|||
|
|||
// Return decrypted string.
|
|||
return plainText; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace API.Model |
|||
{ |
|||
public class GoogleAuthenticatorModel |
|||
{ |
|||
public string BarCodeImageUrl { get; set; } |
|||
public string SetupCode { get; set; } |
|||
public string ManualEntryKey { get; set; } |
|||
} |
|||
} |
@ -0,0 +1,137 @@ |
|||
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Authenticate.aspx.cs" Inherits="JMEAgentSystem.WebPages.Account.Authenticate" %> |
|||
|
|||
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %> |
|||
<!DOCTYPE html> |
|||
<html xmlns="http://www.w3.org/1999/xhtml"> |
|||
<head id="Head1" runat="server"> |
|||
|
|||
|
|||
<link href="../../js/jquery/jquery-ui.css" rel="stylesheet" /> |
|||
<link href="../../ui/css/menu.css" rel="stylesheet" /> |
|||
<link href="../../ui/bootstrap/css/bootstrap.min.css" rel="stylesheet" /> |
|||
<link href="../../ui/css/waves.min.css" rel="stylesheet" /> |
|||
<link href="../../ui/css/style.css" rel="stylesheet" /> |
|||
<link href="../../ui/font-awesome/css/font-awesome.min.css" rel="stylesheet" /> |
|||
<script src="../../ui/bootstrap/js/bootstrap.min.js"></script> |
|||
<script src="../../js/functions.js"></script> |
|||
<style> |
|||
/*body {*/ |
|||
/*font-family: Arial, sans-serif;*/ |
|||
/*background-color: #f7f7f7; |
|||
}*/ |
|||
|
|||
.page-wrapper { |
|||
margin: 30px; |
|||
} |
|||
|
|||
.panel-heading { |
|||
background-color: #f7f7f7; |
|||
} |
|||
|
|||
.panel-title { |
|||
font-size: 24px; |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.form-group { |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.form-group label { |
|||
font-weight: bold; |
|||
padding-top: 7px; |
|||
color: black; |
|||
} |
|||
|
|||
.form-control { |
|||
border-radius: 5px; |
|||
box-shadow: none; |
|||
border: 1px solid #ddd; |
|||
} |
|||
|
|||
.btn-primary { |
|||
background-color: #007bff; |
|||
border-color: #007bff; |
|||
} |
|||
|
|||
.btn-primary:hover { |
|||
background-color: #0056b3; |
|||
border-color: #0056b3; |
|||
} |
|||
|
|||
.btn-primary:focus { |
|||
box-shadow: none; |
|||
} |
|||
|
|||
.errormsg { |
|||
color: red; |
|||
padding-left: 5px; |
|||
} |
|||
|
|||
p { |
|||
font-size: 13px; |
|||
color: black; |
|||
} |
|||
</style> |
|||
|
|||
</head> |
|||
<body> |
|||
<form id="form1" runat="server"> |
|||
<contenttemplate> |
|||
<div class="page-wrapper"> |
|||
<div class="tab-content"> |
|||
<div role="tabpanel" class="tab-pane active" id="list"> |
|||
<div class="row"> |
|||
<div class="col-md-8"> |
|||
<div class="panel panel-default "> |
|||
<div class="panel-heading"> |
|||
<h4 class="panel-title">Verify OTP</h4> |
|||
<div class="panel-actions"> |
|||
<a href="#" class="panel-action panel-action-toggle" data-panel-toggle></a> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="panel-body"> |
|||
<div id="msg" runat="server" class="error"> |
|||
<div class="alert alert-danger" runat="server" id="errMsg" visible="false"></div> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label class="col-md-3"> |
|||
User Name : |
|||
</label> |
|||
<div class="col-md-5"> |
|||
<asp:TextBox ID="txtUserId" runat="server" ReadOnly="true" CssClass="form-control"></asp:TextBox> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label class="col-md-3"> |
|||
Enter OTP :<span class="errormsg">*</span> |
|||
</label> |
|||
<div class="col-md-5"> |
|||
<asp:TextBox ID="txtOtp" runat="server" CssClass="form-control"></asp:TextBox> |
|||
</div> |
|||
</div> |
|||
<div class="form-group"> |
|||
<div class="col-md-6 col-md-offset-3"> |
|||
<asp:Button ID="btnVerify" runat="server" Text="Verify" ValidationGroup="user" |
|||
CssClass="btn btn-primary m-t-25" TabIndex="5" OnClick="btnVerify_Click" /> |
|||
|
|||
<%-- <asp:Button ID="btnCancel" runat="server" Text="Cancel" ValidationGroup="user" |
|||
CssClass="btn btn-primary m-t-25" TabIndex="5" OnClick="btnCancel_Click" />--%> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</contenttemplate> |
|||
</form> |
|||
</body> |
|||
</html> |
|||
|
|||
|
|||
|
@ -0,0 +1,64 @@ |
|||
using Common.Helper; |
|||
using Common.Utility; |
|||
using System; |
|||
using Repository.DAO; |
|||
using System.Collections.Generic; |
|||
using System.Data; |
|||
using System.Linq; |
|||
using System.Web; |
|||
using System.Web.UI; |
|||
using System.Web.UI.WebControls; |
|||
using Business.Account; |
|||
using Business.Configuration; |
|||
using Common.Model; |
|||
using API; |
|||
|
|||
namespace JMEAgentSystem.WebPages.Account |
|||
{ |
|||
public partial class Authenticate : System.Web.UI.Page |
|||
{ |
|||
protected GoogleAuthenticatorAPI _auth = new GoogleAuthenticatorAPI(); |
|||
private readonly IAccountServices _accountServices = AutoFacContainer.Resolve<IAccountServices>(); |
|||
|
|||
private readonly string userId = GetStatic.ReadQueryString("referralCode", ""); |
|||
private readonly string password = GetStatic.ReadQueryString("password", ""); |
|||
private readonly string uniqueKey = GetStatic.ReadQueryString("uniqueKey", ""); |
|||
private string ipAddress = ""; |
|||
protected string use2FA = "Y"; |
|||
|
|||
protected void Page_Load(object sender, EventArgs e) |
|||
{ |
|||
|
|||
LoadLoginData(); |
|||
} |
|||
protected void LoadLoginData() |
|||
{ |
|||
txtUserId.Text = userId; |
|||
} |
|||
protected void btnVerify_Click(object sender, EventArgs e) |
|||
{ |
|||
var otp = txtOtp.Text; |
|||
|
|||
if (string.IsNullOrEmpty(uniqueKey)) |
|||
{ |
|||
errMsg.InnerText = "Please contact JME Head office to get QR code for accessing JME Remit system!"; |
|||
errMsg.Visible = true; |
|||
//EnableLogin();
|
|||
return; |
|||
} |
|||
// var response = _accountServices.AuthenticateAgent(userId, otp, uniqueKey);
|
|||
var _dbRes = _auth.Verify2FA(otp, uniqueKey); |
|||
|
|||
if (_dbRes.ErrorCode != "0") |
|||
{ |
|||
errMsg.InnerText = _dbRes.Msg; |
|||
errMsg.Visible = true; |
|||
// EnableLogin();
|
|||
return; |
|||
} |
|||
{ |
|||
Response.Redirect("/WebPages/"); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,80 @@ |
|||
//------------------------------------------------------------------------------
|
|||
// <auto-generated>
|
|||
// This code was generated by a tool.
|
|||
//
|
|||
// Changes to this file may cause incorrect behavior and will be lost if
|
|||
// the code is regenerated.
|
|||
// </auto-generated>
|
|||
//------------------------------------------------------------------------------
|
|||
|
|||
namespace JMEAgentSystem.WebPages.Account |
|||
{ |
|||
|
|||
|
|||
public partial class Authenticate |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Head1 control.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Auto-generated field.
|
|||
/// To modify move field declaration from designer file to code-behind file.
|
|||
/// </remarks>
|
|||
protected global::System.Web.UI.HtmlControls.HtmlHead Head1; |
|||
|
|||
/// <summary>
|
|||
/// form1 control.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Auto-generated field.
|
|||
/// To modify move field declaration from designer file to code-behind file.
|
|||
/// </remarks>
|
|||
protected global::System.Web.UI.HtmlControls.HtmlForm form1; |
|||
|
|||
/// <summary>
|
|||
/// msg control.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Auto-generated field.
|
|||
/// To modify move field declaration from designer file to code-behind file.
|
|||
/// </remarks>
|
|||
protected global::System.Web.UI.HtmlControls.HtmlGenericControl msg; |
|||
|
|||
/// <summary>
|
|||
/// errMsg control.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Auto-generated field.
|
|||
/// To modify move field declaration from designer file to code-behind file.
|
|||
/// </remarks>
|
|||
protected global::System.Web.UI.HtmlControls.HtmlGenericControl errMsg; |
|||
|
|||
/// <summary>
|
|||
/// txtUserId control.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Auto-generated field.
|
|||
/// To modify move field declaration from designer file to code-behind file.
|
|||
/// </remarks>
|
|||
protected global::System.Web.UI.WebControls.TextBox txtUserId; |
|||
|
|||
/// <summary>
|
|||
/// txtOtp control.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Auto-generated field.
|
|||
/// To modify move field declaration from designer file to code-behind file.
|
|||
/// </remarks>
|
|||
protected global::System.Web.UI.WebControls.TextBox txtOtp; |
|||
|
|||
/// <summary>
|
|||
/// btnVerify control.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Auto-generated field.
|
|||
/// To modify move field declaration from designer file to code-behind file.
|
|||
/// </remarks>
|
|||
protected global::System.Web.UI.WebControls.Button btnVerify; |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue