I have this Action method in ASP.NET MVC 5:
namespace LDAPMVCProject.Controllers
{
public class HomeController : Controller
{
public ActionResult UsersInfo(string username, string password)
{
DomainContext result = new DomainContext();
try
{
// create LDAP connection object
DirectoryEntry myLdapConnection = createDirectoryEntry();
string ADServerName = System.Web.Configuration.WebConfigurationManager.AppSettings["ADServerName"];
string ADusername = System.Web.Configuration.WebConfigurationManager.AppSettings["ADUserName"];
string ADpassword = System.Web.Configuration.WebConfigurationManager.AppSettings["ADPassword"];
using (var context = new DirectoryEntry("LDAP://mydomain.com:389/DC=mydomain,DC=com", ADusername, ADpassword))
using (var search = new DirectorySearcher(context))
{
// validate username & password
using (var context2 = new PrincipalContext(ContextType.Domain, "mydomain.com", ADusername, ADpassword))
{
bool isvalid = context2.ValidateCredentials(username, password);
if !(isvalid)
return **** // authentication error
}
// create search object which operates on LDAP connection object
// and set search object to only find the user specified
// DirectorySearcher search = new DirectorySearcher(myLdapConnection);
// search.PropertiesToLoad.Add("telephoneNumber");
search.Filter = "(&(objectClass=user)(sAMAccountName=test.test))";
// create results objects from search object
// user exists, cycle through LDAP fields (cn, telephonenumber etc.)
SearchResult r = search.FindOne();
ResultPropertyCollection fields = r.Properties;
foreach (String ldapField in fields.PropertyNames)
{
if (ldapField.ToLower() == "telephonenumber")
{
foreach (Object myCollection in fields[ldapField])
{
result.Telephone = myCollection.ToString();
}
}
else if (ldapField.ToLower() == "department")
{
foreach (Object myCollection in fields[ldapField])
{
result.Department = myCollection.ToString();
}
}
// }
}
if (result.Telephone == null)
return ***** //Telephone is empty
if (result.Department)
return **** // department is empty
string output = JsonConvert.SerializeObject(result);
return Content(output, "application/json");//success
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" e.ToString());
}
return View(result);
}
}
}
The action method acts as an API endpoint for our web application, where the API accepts username & password, and does the following:
Validate the username/password against Active Directory
If valid; check if the telephone number is empty >> if so return an error
If valid; check if department is empty >> if so return an error
If valid and info found; return the department & telephone for the user
Now I am a bit confused on how I need to return the JSON for the first 3 points? Should I always return http 200 with a status message (Status : "success" OR Status: "failed")? or if the username/password validation failed then i should return http 401 without having to return any JSON content?
Can anyone help me with this?
I need to write the action method in a standard way that can be consumed by 3rd party application.
Second question: what do I need to return in case the code raised an exception?
Thanks
CodePudding user response:
There are a lot of ways to go about this and ultimately you want to have your endpoint behave in a way that whoever is consuming your endpoint expects.
I stumbled across this as an interesting way to handle nuanced errors in a request to your endpoint. Even though this is used for Graph API, you could use the concept for your needs. https://developers.facebook.com/docs/graph-api/guides/error-handling. The TL;DR is to have a standardized json response like:
{
"error": {
"message": "Message describing the error",
"type": "OAuthException",
"code": 190,
"error_subcode": 460,
"error_user_title": "A title",
"error_user_msg": "A message",
"fbtrace_id": "EJplcsCHuLu"
}
}
CodePudding user response:
The HTTP statuse codes are very flexable and can be confused to tell when to use what. My advice:
- Identify the Http status family (X00)
- 100s: Informational codes: the server acknowledges the request initiated by the browser and that it is being processed (100–199).
- 200s: Success codes: request received, understood, processed and expected info relayed to browser (200–299).
- 300s: Redirection codes: a different destination has been substituted for the requested resource; further action by the browser may be required (300–399).
- 400s: Client error codes: website or page not reached; page unavailable or there was a technical problem with the request (400–499).
- 500s: Server error codes
- Search for the specific Http status code for your response (2XX) here some exemples for the 200 family:
- 201: Created. Request fulfilled; new resource created. Typical response after POST requests.
- 202: Accepted. Browser request accepted, still in process. May or may not succeed.
For your example I would return:
- 403: Forbidden - if the user credentials are wrong.
- 200: Ok - if everythig works well (all the info returned).
The other option is a little tricky, when the user is authenticate but have no valid data. you can return:
- 204: No content - because the user is auth but has no data
- 500: internal server error - because the server cant return the requested object
- 404: Not found - (not my personal chois but it is an option)
It also depends on your client and you preferences.
Happy coddind :)