Unbreakable Unbreakable - 23 days ago 7
ASP.NET (C#) Question

How to return correct error message to User when log in is restricted

I am new to ASP.Net web development and I am stuck in handling the exceptions when log in is restricted.
Question: I have owner log in and tenant log in. Now owner can restrict the log in for Tenant. But when the log in is restricted I want to show to the tenant that their credential is correct but log in is restricted.

Below is what I have tried till now.

Controller

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LoginSubmit(LoginMV userData)
{
if (userData != null)
{
UserMV authenticatedUser = AuthenticateTenant(userData.Username, userData.Password);
if (authenticatedUser == null)
{
ModelState.AddModelError("Invalid credentials");
}
else
{
//Do the login
}
}

return View("Login", userData);
}


User data from API

private static UserMV AuthenticateTenant(string username, string password)
{
Res response = mdlAPI.AuthenticateTenant(username, password);
try{
response.Validate(username);
}

UserMV result = new UserMV()
{
DisplayName = response.objTenant.LastName + ", " + response.objTenant.FirstName
};
return result;
}


FYI
API Response is
response.ResultCode = Restricted
.

Validate

public static void Validate(this Res response, string username)
{
if (response.ResultCode != Enumerations.AuthResultCode.Successful)
{
string additionalDetails = "";
if (response.ResultCode == Enumerations.AuthResultCode.Restricted)
{
additionalDetails = "Login Restricted.";
}
throw new ValidationException(additionalDetails);
}
}


So in the above method
additionalDetails
get set to "Login Restrcited"
and the ValidationException is called. Also, since the exception is raised the UserMV object will not get created in the
AuthenticateTenant function
.

ValidationException

public class ValidationException : Exception
{
public ValidationException(string message) : base (message)
{ }
}


After all of this the sequence of code returns to the Controller. As the userMV is NULL the error message that gets displayed is "Invalid credentials". Have I missed something.

I am getting the exception properly in ValidationException class. Do I need to do something else for the exception to be displayed to the user. I am a beginner so pardon my coding standards. Please guide me what else I need to do to display the 'additional detail` stuff to the tenant.

View File:

@using (Html.BeginForm("LoginSubmit", "Security", FormMethod.Post, new { id = "simLogin" }))
{
@Html.AntiForgeryToken()

<div class="form-horizontal-width-inherit">
@Html.HiddenFor(model => model.ReturnUrl)

@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.ValidationMessageFor(model => model.Username, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.Username, htmlAttributes: new { @class = "control-label ignoreSpacing col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Username, new { @class = "form-control" } )
</div>
</div>

<div class="form-group">
@Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label ignoreSpacing col-md-2" })
<div class="col-md-10">
@Html.PasswordFor(model => model.Password, new { @class = "form-control" } )
</div>
</div>

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Login" class="btn btn-default" />
</div>
</div>
</div>
}

Answer

You seem to be relying on the AuthenticateTenant() to check the credentials for you and also to return the authentication result.

But, internally you're calling Validate() that in turn is throwing an exception. That exception is changing the control flow of the code. Currently, the only code that seems to catch it is either some error filter you have or it's propagated down to IIS and the generic HTTP 500 is being displayed.

I would suggest not to throw an exception as part of the AuthenticateTenant() method but rather return a null (or false, if you're willing to change the method signature).

Once you're back in control of the flow, you can rely on the returned result to rightfully call ModelState.AddModelError() with the proper message.