Is validating a userId (or any other data extracted from an authentication token) necessary? - asp.net-web-api

In my controller action as have something like this:
[HttpGet]
[ActionName("approve")]
[Authorize(Policy = "Approve")]
public IActionResult GetEntitiesToBeApproved()
{
var stringUserId = User.Claims.FirstOrDefault(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;
Guid.TryParse(stringUserId, out var userId);
if (userId == default(Guid))
{
return StatusCode((int)HttpStatusCode.BadRequest, ConstantValues.InvalidUserId);
}
//service calls etc.
return Ok();
}
Is there any point in checking that the userId is valid (non-default) or can I skip it?

You can skip it, Authorize filter attribute check it for You.

Related

I Want to execute second Login(contactnumber,password) but after passing the argument it is still calling the list login method How to resolve this?

I Want to execute second Login(contactnumber,password) but after passing the argument it is still calling the list login method How to resolve this?
[HttpGet]
public IEnumerable<UserDetail> Login()
{
using (HeandSheEntities entities = new HeandSheEntities())
{
return entities.UserDetails.ToList();
}
}
[System.Web.Http.AcceptVerbs("GET")]
[System.Web.Http.HttpGet]
public HttpResponseMessage Login(String ContactNumber, String Password) {
{ String Upass = encryption(Password);
using (HeandSheEntities entities = new HeandSheEntities())
{
bool userphone = entities.UserDetails.Any(u => u.UserContactNumber.Equals(ContactNumber));
bool userpass = entities.UserDetails.Any(u => u.UserPassword.Equals(Upass));
if (ModelState.IsValid && userphone && userpass)
{
var user = entities.UserDetails.FirstOrDefault(u => u.UserContactNumber.Equals(ContactNumber));
if (user != null)
return Request.CreateResponse(HttpStatusCode.OK, user, new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
else
return Request.CreateResponse(HttpStatusCode.BadRequest, "Either Contact Number or password is not correct", new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "Either Contact Number or password is not correct", new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
}
}
}
You use the same name for both action methods with the same http verb. You cannot overload action methods. See here and here. Semantically you should use POST http method for changing state (for example logging user) and it will work.
[HttpPost]
public HttpResponseMessage Login(String ContactNumber, String Password)

How to get user context during Web Api calls?

I have an web front end calling an ASP Web Api 2 backend. Authentication is managed with ASP Identity. For some of the controllers I'm creating I need to know the user making the call. I don't want to have to create some weird model to pass in including the user's identity (which I don't even store in the client).
All calls to the API are authorized using a bearer token, my thought is the controller should be able to determine the user context based on this but I do not know how to implement. I have searched but I don't know what I'm searching for exactly and haven't found anything relevant. I'm going for something like...
public async Task<IHttpActionResult> Post(ApplicationIdentity identity, WalkthroughModel data)
Update
I found the below which looked very promising... but the value is always null! My controller inherits from ApiController and has an Authorize header.
var userid = User.Identity.GetUserId();
Update 2
I have also tried all of the solutions in Get the current user, within an ApiController action, without passing the userID as a parameter but none work. No matter what I am getting an Identity that is valid and auth'd, but has a null UserID
Update 3
Here's where I'm at now.
[Authorize]
[Route("Email")]
public async Task<IHttpActionResult> Get()
{
var testa = User.Identity.GetType();
var testb = User.Identity.GetUserId();
var testc = User.Identity.AuthenticationType;
var testd = User.Identity.IsAuthenticated;
return Ok();
}
testa = Name: ClaimsIdentity,
testb = null,
testc = Bearer,
testd = true
The user is obviously authenticated but I am unable to retrieve their userID.
Update 4
I found an answer, but I'm really unhappy with it...
ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
string username = identity.Claims.First().Value;
That gets me the username without any db calls but it seems very janky and a pain to support in the future. Would love if anyone had a better answer.
What if I need to change what claims are issued down the road? Plus any time I actually need the user's id I have to make a db call to convert username to ID
A common approach is to create a base class for your ApiControllers and take advantage of the ApplicationUserManager to retrieve the information you need. With this approach, you can keep the logic for accessing the user's information in one location and reuse it across your controllers.
public class BaseApiController : ApiController
{
private ApplicationUser _member;
public ApplicationUserManager UserManager
{
get { return HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
}
public string UserIdentityId
{
get
{
var user = UserManager.FindByName(User.Identity.Name);
return user.Id;
}
}
public ApplicationUser UserRecord
{
get
{
if (_member != null)
{
return _member ;
}
_member = UserManager.FindByEmail(Thread.CurrentPrincipal.Identity.Name);
return _member ;
}
set { _member = value; }
}
}
I use a custom user authentication (I dont use AspIdentity because my existing user table fields was far different from IdentityUser properties) and create ClaimsIdentity passing my table UserID and UserName to validate my bearer token on API calls.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
User user;
try
{
var scope = Autofac.Integration.Owin.OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext);
_service = scope.Resolve<IUserService>();
user = await _service.FindUserAsync(context.UserName);
if (user?.HashedPassword != Helpers.CustomPasswordHasher.GetHashedPassword(context.Password, user?.Salt))
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
catch (Exception ex)
{
context.SetError("invalid_grant", ex.Message);
return;
}
var properties = new Dictionary<string, string>()
{
{ ClaimTypes.NameIdentifier, user.UserID.ToString() },
{ ClaimTypes.Name, context.UserName }
};
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
properties.ToList().ForEach(c => identity.AddClaim(new Claim(c.Key, c.Value)));
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties(properties));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(identity);
}
And how I use the ClaimsIdentity to retrieve my User table details on User ApiController Details call.
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("Details")]
public async Task<IHttpActionResult> Details()
{
var user = await _service.GetAsync(RequestContext.Principal.Identity.GetUserId<int>());
var basicDetails = Mapper.Map<User, BasicUserModel>(user);
return Ok(basicDetails);
}
Notice the
ClaimTypes.NameIdentifier = GetUserId() and ClaimTypes.Name = GetUserName()

How do I validate for a empty query string parameter in asp.net mvc3

I want to validate for a empty Id value in the url.
../Task/EditEmployee/afccb22a-7cfd-4be5-8f82-9bd353c13b16
I want that if the Id is empty
../Task/EditEmployee/
Than redirect the user to a certain page.
public ActionResult EditEmployee(Guid Id)
{
//Some code in here
}
It may not be the best solution but you can take id parameter as string and try to parse it like this:
public ActionResult EditEmployee(string id)
{
if(string.IsNullOrWhiteSpace(id))
{
// handle empty querystring
}
else
{
Guid guid;
if (Guid.TryParse(id, out guid))
{
//Some code in here
}
}
}
Or
You can also create a regex constraint on the route but that may be too complicated and hard to understand. Map this route before the default one.
routes.MapRoute(
"TastEditEmployee",
"Task/EditEmployee/{id}",
new { controller = "Task", action = "EditEmployee" },
new { id = #"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$" }
);
Then you can use id parameter as Nullable Guid.
public ActionResult EditEmployee(Guid? id)
{
//do something
}
Since Guid is a struct, the value of Id will be Guid.Empty if it was omitted. You can check for that.
public ActionResult EditEmployee(Guid Id)
{
if (Id == Guid.Empty) throw new ArgumentException("Id not specified.");
}

IsUserInRole not working in CSHTML

I have this code, but I don't know why this is not working properly. I have a custom role provider created.
#if (Roles.IsUserInRole(User.Identity.Name, "Manager"))
{
<li>#Html.ActionLink("User Management", "Index", "User")</li>
}
This is the custom code, the rest wasn't modified.
public override bool IsUserInRole(string username, string roleName)
{
UserRoleType usrt = (from usr in db.Users
join usrRole in db.UserRoles on usr.UserID equals usrRole.UserID
where usr.Email == username
select usrRole.UserRoleType).FirstOrDefault();
if (roleName.Split(',').Contains(usrt.UserRoleTypeName))
return true;
return false;
}
This does work when I do this:
UserRoleProvider roleProvider = System.Web.Security.Roles.Provider as UserRoleProvider;
if (roleProvider.IsUserInRole(httpContext.User.Identity.Name, Roles) || String.IsNullOrEmpty(Roles))
return true;
EDIT:
public override string[] GetRolesForUser(string roleName)
{
return db.UserRoleTypes.Select(u => u.UserRoleTypeName).ToArray();
}
Turns out GetRolesForUser was written in correctly and it was pulling all the Users so it authenticated based on ALL users, which means it was in the first place.
Re-read the documentation to get my answer here.
http://msdn.microsoft.com/en-us/library/system.web.security.roleprovider.getrolesforuser.aspx
It appears that User.IsInRole(rolename) uses MembershipProvider.GetRolesForUser(username)
It took me a while to figure that out.

MVC3 Edit customer with username

I am trying to edit customer with username which is using User.Identity.Name.
I don't know how to write Where condition in controller.
It looks easy. Could you help me? thanks.
Here is my coding.
[Authorize]
public ActionResult Edit()
{
//the username gets username through User.Identity.Name.
string username = User.Identity.Name;
//How can I write below coding?
//In DB, it has userName field.
Customer customer = db.Customer.Where(userName = username);
return View(customer);
}
[HttpPost]
public ActionResult Edit(Customer customer)
{
if (ModelState.IsValid)
{
db.Entry(customer).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(customer);
}
You need to learn how lambda expressions work:
.Where(c => c.UserName == username)
c is the implicitly-typed parameter.
Also, if you want a single result, you should call FirstOrDefault() instead; Where() returns a sequence.
Customer customer = db.Customer.Single(c=>c.UserName == username)
throws exception if returns one than more matching element
or
Customer customer = db.Customer.SingleOrDefault(c=>c.UserName == username);
returns null if returns more than one matching element

Resources