Friday, November 24, 2017

Authentication in wcf rest service

Steps.

  1. Create Authenticate method which authenticates an user and also returns a token which can be used for next subsequent requests.
  2. Create a login class in business layer which has business logic to validate the user credential against database and generate the token if the credentials are valid
  3. Create a method to validate the token which would come in next subsequent requests



  • Create Authenticate method in *SVC.cs file which takes userId and password as a parameter

//Below method authenticates the user and sends a token for authenticated user which can be used for //next subsequent requests.

public stream Authenticate(string userID, string password) {<br /> &nbsp;Stream strJSONResponse = null;<br /> &nbsp;Login Obj = new + 6(); // This is your login class in business layer explained in point #2 below<br /> &nbsp;//string deviceId = string.Empty &nbsp; //Optional if you are coding for mobile devices then can be used<br /> &nbsp;WebHeaderCollection headers = WebOperationContext.Current.IncomingRequest.Headers;<br /> &nbsp;//WebHeaderCollection &nbsp;- Namespace | System.net.WebHeaderCollection<br /> &nbsp;//WebOperationContext - Namespace | System.serviceModel.web.WebOperationContext<br /> &nbsp;try {<br /> &nbsp; foreach(string headerName in headers.Allkeys) {<br /> &nbsp; &nbsp;//If you want retrieve device ID from header<br /> &nbsp; &nbsp;if (headerName == 'desiredDeviceId') {<br /> &nbsp; &nbsp; deviceId = headers[headername];<br /> &nbsp; &nbsp;}<br /> &nbsp; &nbsp;strJSONResponse = obj.Authenticate(userID, password, deviceId)<br /> &nbsp; &nbsp;return strJSONResponse;<br /> &nbsp; }<br /> &nbsp;}<br /> }<br /> <br /> <br />

  • Login class in business layer having implementation of Authenticate method


public class Login {
 public stream Authenticate(string usersId, string password, string deviceId) {
   outAuthentication objOutAuthentication = new outAuthentication();
   try {
    objOutAuthenticaton.successFlag = Decimal.One.ToString();
    if (deviceId == String.Empty) {
     objOutAuthenticaton.successMessage = "Device Id Absent";
    } else {
     objOutAuthenticaton.successMessage = "Success";
     bool bIsAuthenticatedUser = false;
     bool bIsActiveUser = false;
     DataTable dtUser = objDAL.GetUserCredentials(usersId);
     if (dtUser != null && dtUser.Rows.count > 0) {
      Decrypt objDecrypt = new clsUtilities.Decrypt();
      if `(userID.ToUpper() == convert.ToString((dtUser.Rows[0][0]).Trim().ToUpper && password == objDecrypt.DecryptString(Convert.ToString(dtUser.Rows[0][1])))
{
bIsAuthenticatedUser = true;
}
bIsAtctiveUser = Convert.ToBoolean(dtUser.Rows[0][2]);
}
}
objOutAuthenticaton.status = bIsAuthenticatedUser == true? Decimal.One.ToString() : Decimal.Zero.ToString();

if(bIsActiveUser)
{
if(bIsAuthenticatedUser)
{
Datatable dt = new DataTable();
dt = objDAL.GetUserDetail(userId)
if ( dt!= null && dt.Rows.count>0)
{
//Below code to send Authenticate key to the calling application so that it can be used for subsequent //request by authorized user. User won't have to provide ID and pwd again and again
objOutAuthenticaton.authKey = GenerateToken(usersId, "AnyStringKey", deviceId, DateTime.UtcNow.Ticks);

//Insert autorization token in session token table
InsertAuthToken(objOutAuthenticaton.authKey,DateTimeUtcNow);
}
}
}
}
}


//Database layer


  • 3. Get user credentials saved in database

public DataTable GetUserCredentials(string strUserId) {
 DataTable dt = new DataTable();
 ConnectionClass objConnection = new ConnectionClass();
 try {
  SqlParameter[] objParams = {
   new SqlParameters("UsersID", SqlDbType.Nvarchar) {
    Value = strUserId
   }
  };
  dt = ExecuteReaderDataTableSP("Login_usp_GetUserCredentials, objParams);
  }
 }

}



  • 4. Generate Token

public static string GenerateToken(string userName, string password, string deviceID, long ticks) {
 string hash = string.Join(":", new string[] {
  userName,
  deviceID,
  ticks,
  ToString()
 });
 string hashLeft = string.Empty;
 string hashRight = string.Empty

 using(HMAC hmac = HMACHA256.Create("HmacSHA256")) {
  hmac.key = Encoding.UTF8.GetBytes(GetHashedPassword(password));
  hmac.computeHash(Encoding.UTF8.GetBytes(hash));
  hashLeft = Convert.ToBase64String(hmac.Hash);
  hashRight = string.Join(":", new string[] {
   userName,
   deviceID,
   ticks.ToString()
  });
 }
 return Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join(":", hashLeft, hashRight)));
}



5. Insert GeneratedToken into database
public bool InsertAuthToken(string token, DateTime currentDate) {
  ConnectionClass objConnection = new ConnectionClass();
  try {
   SqlParameter[] objParams = {
    new SqlParameters("token", SqlDbType.Nvarchar) {
     Value = token
    } {
     new SqlParameters("currentDate", SqlDbType.Nvarchar) {
      Value = currentDate
     }
    };
    int iCount = objConnection.ExecuteNonQuerySP("usp_InsertAuthToken", objParams);
    return icount > 0 ? true : false;
   }
  }


  • 6. IsTokenValid

Call below method in subsequent requests to verify the token sent by client is valid or not

public static string IsTokenValid(string token, string userId, string dvcId) {
 string message = String.Empty;
 try {
  string key = Encoding.UTF8.GetString(Convert.FromBase64String(token));
  int _expirationMinutes = Convert.ToInt32("20").ToString();
  // Split the parts,
  string[] parts = key.Splt(new char[] {
   ':'
  });
  if (parts.Lenth == 4) {
   string hash = parts[0];
   string username = parts[1];
   string deviceId = parts[2];
   long ticks = parts[3];
   string servicePassword = "AnyStringKey";
   string computedToken = GenerateToken(username, servicePassword, deviceId, ticks);

   if (token == computedToken) {
    string modifiedTime = GetModifiedDts(token); //check expiry date of token
    if (!string.IsNullOrEmpty(modifiedTime)) {
     boll expired = Math.Abs((DateTime.UtcNow - Convert.ToDateTime(modifiedTime)).TotalMinutes) > 20;

     if (expired) {
      message = "Auth Key Expired, please login again";
      //Delete token from session table of database
     } else {
      //update the latest timestamp in database against that token so that session time keep on extending if //attempt is valid
      DateTim currentDate = DateTime.UtcNow;
      //UpdateAuthToken(token,CurrentDate)
      message = "Authentication Key is valid";
     } |


    }
   }

   //Check whether the user name is proper from header
   if (username == userId && deviceId == dvcId) {}
  }
 }
}



Stored Procedures :

1. usp_GetUserCredentials

CREATE PROCEDURE [dbo].[usp_GetUserCredentials] @usersId nVarchar(50)
AS
BEGIN
SELECT U.UsersId,U.Password, U.isActive
FROM [DBO].[users] U
Where U.usersId = @usersId
AND @usersId IS NOT NULL;
END

2. usp_InsertAuthToken

CREATE PROCEDURE [dbo].[usp_InsertAuthToken]
@token nvarchar(max),
@curentDate DateTime
As
BEGIN
Insert INTO [DBO].SESSIONTOKENS] VALUES (ltrim(rtrim(@token, @currentDate)
END