#Code Web.Api user authentication using secure salted hash password

Massimo Mannoni
5 min readJan 22, 2019

Use a web.api service to verify users credentials

Introduction

We have a few applications running on different devices (server, mobile, tablet) and we would like to provide a service able to verify the user credentials. In this story we are going to create a web Api which accepts a Json representation of a single user credential and returns a bool parameter “isValid” once checked.

Prerequisites

Asp.Net Core 2.1 , Sql Server, TSql

Implementation

Create a table to store the user credential and other stuff.

CREATE TABLE [dbo].[UsersPlatform]([UserPlatformID] [bigint] IDENTITY(1,1) NOT NULL,
[UserID] [bigint] NOT NULL,
[DominioID] [tinyint] NULL,
[RiskProfileID] [tinyint] NULL,
[UserName] [varchar](8) NOT NULL,
[Password] [varchar](80) NULL,

[LevelID] [tinyint] NOT NULL,
[ActivationDate] [datetime] NULL,
[CloseDate] [datetime] NULL,
[CreationDate] [datetime] NOT NULL
CONSTRAINT [PK_UsersPlatform] PRIMARY KEY CLUSTERED
(
[UserPlatformID] ASC
)
WITH
(PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

To complete the database scripts we need to create a store procedure to retrive the password saved for a specific username

CREATE PROCEDURE [dbo].[GetAuthHash]@username varchar(8) //input parameterAS
BEGIN
SET NOCOUNT ON; SELECT
UsersPlatform.UserID,
UsersPlatform.Password

FROM UsersPlatform
WHERE
UsersPlatform.UserName = @username AND
UsersPlatform.CloseDate IS NULL
END
GO

Important : in this story we will use the integrated security authentication to login on our db. Remember to use different servers and set up specific firewall rules between them to improve your application safety.

In our web.api project, add the connect string in the appsetting.json file.

Connection string for Sql Server instance

In the Dal (Data Access Layer) directory we can create the classes involved in the sql data interaction.

I often use a base class per helper method and one derived class per each table with its specific method. Consequently, as you can imagine, we’ll not be using an ORM ;)

using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using Microsoft.Extensions.Configuration;
namespace IT.Users.Dal
{
public class DBFunctions
{
..... #region Helper Methods public DataSet GetDataSet(SqlCommand cmd)
{
....
}
protected SqlParameter Param(string name, object value, SqlDbType type)
{
SqlParameter param = new SqlParameter(name, value);
param.SqlDbType = type;
return param;
}
protected SqlCommand NewCommand(SqlConnection connection, string text, CommandType type, params SqlParameter[] parameters)
{
var command = new SqlCommand(text, connection);
command.CommandType = type;
command.Parameters.AddRange(parameters);
return command;
}
protected SqlConnection NewConnection()
{
var connection = new SqlConnection(ConnectionString);
return connection;
}
private string ConnectionString
{
get {
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configuration = builder.Build(); return configuration.GetConnectionString("SqlServer");
}
}
#endregion
}
}

The DBFunction class provides a SqlConnection calling the NewConnection method and a SqlCommand calling the NewCommand. The ConnectionString method retrieves the connection string reading the appsetting.json file.

The next step concerns the DBAuthRequest class. In this class we have a method used to call the store procedure and read the data from our table.

public class DBAuthRequest : DBFunctions
{
public async Task<KeyValuePair<long,string>> GetHashCode(AuthRequest auth)
{
KeyValuePair<long, string> idHash; try
{
using (SqlConnection conn = NewConnection())
{
using (SqlCommand cmd = NewCommand(conn, "GetAuthHash", CommandType.StoredProcedure, Param("@username", auth.Username, SqlDbType.VarChar)))
{
await conn.OpenAsync();
cmd.CommandTimeout = DataBase.commandTimeout;
using (var dr = await cmd.ExecuteReaderAsync())
{
while (await dr.ReadAsync())
{
idHash = new KeyValuePair<long, string> ((long)dr["userID"], dr["password"].ToString());
}
dr.Close();
}
conn.Close();
}
}
}
catch (Exception ex)
{
throw ex;
}
return idHash;
}
}

The async Task opens a connection to the Sql Server instance, calls the “GetAuthHash” store procedure -passing the “username”- and returns a KeyValuePair containing the userID and the hash salted password.

Having in the DB the hash-salted password, we need to have a method that verifys if the password provided to the api, once encrypted, is equal to the saved one.

The “salt” uses the userID so the encrypt method should be the following:

public class Security
{
public class PasswordHash
{
public static string Create(long userID, string password)
{
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
// the salt used for derivation process
salt: BitConverter.GetBytes(userID),

// random function for key derivation using SHA256 hash function
prf: KeyDerivationPrf.HMACSHA256,
// number of iteractions of random function
iterationCount: 10000,
// desired length in bytes
numBytesRequested: 256 / 8));
return hashed;
}
}
}

The last 3 steps consist in the creation of the auth model, a controller and a business logic layer class.

public class AuthRequest
{
public string Username { get; set; }
public string Password { get; set; }
public bool IsValid { get; set; }
public static async Task<KeyValuePair<long, string>> GetHashCode (AuthRequest auth)
{
DBAuthRequest dbAuth = new DBAuthRequest();
KeyValuePair<long, string> idHash;
try
{
idHash = await Task.FromResult(result:dbAuth.GetHashCode(auth).Result);
}
catch (Exception)
{
throw;
}
finally
{
dbAuth = null;
}
return idHash;
}
}

The Model: it is basically an AuthRequest model with 3 properties and a method. It instances a DBAuthRequest class and returns the userID and the salt-hash password saved on the SqlServer.

The BLL: it is a simple class used to compare the data.

public class Authentication
{
public static async Task<AuthRequest> GetValidation(AuthRequest auth)
{
try {
KeyValuePair<long, string> idHash = await Task.FromResult(result: AuthRequest.GetHashCode(auth).Result);
if (idHash.Key > 0)
{
auth.IsValid = (Security.PasswordHash.Create(idHash.Key, auth.Password) == idHash.Value);
}
}
catch (Exception){throw;} return auth; }
}

The static async method compares the hash created with the saved one and, if it is equal, modifies the “isValid” property of the AuthRequest model to “true”.

This story finishes with the controller.

[Route("api/[controller]")]
public class AuthRequestController : Controller
{
....
// POST api/values[HttpPost]
public async Task<AuthRequest> PostAsync([FromBody]AuthRequest authRequest)
{
if (authRequest != null)
{
authRequest = await Task.FromResult(result: Authentication.GetValidation(authRequest).Result);
}

return authRequest;
}
}

The AuthRequestController receives a Json representation posted by an application (hopefully under a HTTPS connection) an returns the same modified representation in case the passwords match.

Here below the full project:

Important: in this case, the choice to have the password passed to the web api in clear is because we won’t have the hashing algorithm implemented in different solutions, and that is a good way to protect the whole repository.

Cheers ;)

Massimo M.

--

--