How can I easily check whether the user submitting a query belongs to them or not in .net core? - asp.net

Authorization Set
services.AddAuthorization(options =>
{
options.AddPolicy("MustNutritionist", policy =>
policy.RequireClaim("nutritionistId"));
});
Controller
NutritionistUpdateModel have id field.
[Authorize(Policy = "MustNutritionist")]
public BaseResponseModel PostEdit([FromForm] NutritionistUpdateModel nutritionistUpdateModel)
{
try
{
var result = nutritionistService.EditNutritionist(nutritionistUpdateModel);
if (result)
{
return new SuccessResponseModel<bool>(result);
}
else
{
return new BaseResponseModel(ReadOnlyValues.NutritionistNotFound);
}
}
catch (Exception ex)
{
return new BaseResponseModel(ex.Message);
}
}
Token Generation Claim
claims.Add(new Claim("nutritionistId", nutritionistId.ToString()));
Problem
I want to check equation of NutritionistUpdateModel.Id and Claims.nutritionistId. I can check with below code.But i must write lots of if else statement.Is there any easy way ?
private bool ChechNutritionistAuthorize(int nutritionistId)
{
var currentUser = HttpContext.User;
var nutritionistIdClaim=Int32.Parse(currentUser.Claims.FirstOrDefault(c => c.Type == "NutritionistId").Value);
if (nutritionistIdClaim == nutritionistId)
{
return true;
}
else
{
return false;
}
}

Using extension method like this
public static class IdentityExtensions
{
public static bool ValidateNutritionistId(this ClaimsPrincipal principal, int nutritionistId)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
int.TryParse(principal.Claims.FirstOrDefault(c => c.Type == "NutritionistId").Value, out int nutritionistIdClaim);
return nutritionistIdClaim == nutritionistId;
}
}
and you can use like this
HttpContext.User.ValidateNutritionistId(your id here )
and you also need to add using statement and reuse same method in all of your Controllers

Related

Cannot post update to database. not all code paths return a value

[HttpPost]
public ActionResult UpdateDetail(User user)
{
bool Status = false;
string message = "";
// Model Validation
if (ModelState.IsValid)
{
using (UsersDatabaseEntities ude = new UsersDatabaseEntities())
{
var v = ude.Users.Where(a => a.Email == User.Identity.Name).FirstOrDefault();
user = v;
ude.Entry(User).State = EntityState.Modified;
ude.SaveChanges();
}
return View(user);
}
}
I keep on getting an error while saving data to the database.
UpdateDetail worked while retrieving message, but i keep getting error when saving.
Your issue is if your ModelState.IsValid == false, then you are not returning anything. I put a comment in code below where it is.
Depending on what your logic needs to do, would determine what needs to be returned if IsValid == false
public ActionResult UpdateDetail(User user)
{
bool Status = false;
string message = "";
// Model Validation
if (ModelState.IsValid)
{
using (UsersDatabaseEntities ude = new UsersDatabaseEntities())
{
var v = ude.Users.Where(a => a.Email == User.Identity.Name).FirstOrDefault();
user = v;
ude.Entry(User).State = EntityState.Modified;
ude.SaveChanges();
}
// this is your issue, this needs to be outisde the if statement, or you have to do an else and return null (or whatever you need to based off your logic)
return View(user);
}
}
Keep return statement outside of If statement. this would fix your error.If model is valid model updated with user details from database will be pushed to View. other wise same user model will be pushed to the view.
[HttpPost]
public ActionResult UpdateDetail(User user)
{
bool Status = false;
string message = "";
// Model Validation
if (ModelState.IsValid)
{
using (UsersDatabaseEntities ude = new UsersDatabaseEntities())
{
var v = ude.Users.Where(a => a.Email == User.Identity.Name).FirstOrDefault();
user = v;
ude.Entry(User).State = EntityState.Modified;
ude.SaveChanges();
}
}
return View(user);
}

How do I remove the charset from Content-Type in a ASP.NET Core MVC response?

No matter what I try I cannot seem to remove the ; charset=utf-8 part from my response's Content-Type header.
[HttpGet("~/appid")]
// Doesn't work
//[Produces("application/fido.trusted-apps+json")]
public string GetAppId()
{
// Doesn't work
Response.ContentType = "application/fido.trusted-apps+json";
// Doesn't work
//Response.ContentType = null;
//Response.Headers.Add("Content-Type", "application/fido.trusted-apps+json");
return JsonConvert.SerializeObject(new
{
foo = true
});
}
I always get application/fido.trusted-apps+json; charset=utf-8 when I only want application/fido.trusted-apps+json.
Note: This is to conform with the FIDO AppID and Facet Specification v1.0 for U2F which states:
The response must set a MIME Content-Type of "application/fido.trusted-apps+json".
I went with the following approach, using middleware to replace the header on the way out. Seems kinda hacky to have to use middleware like this:
Middleware
public class AdjustHeadersMiddleware
{
private readonly RequestDelegate _next;
public AdjustHeadersMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext, CurrentContext currentContext)
{
httpContext.Response.OnStarting((state) =>
{
if(httpContext.Response.Headers.Count > 0 && httpContext.Response.Headers.ContainsKey("Content-Type"))
{
var contentType = httpContext.Response.Headers["Content-Type"].ToString();
if(contentType.StartsWith("application/fido.trusted-apps+json"))
{
httpContext.Response.Headers.Remove("Content-Type");
httpContext.Response.Headers.Append("Content-Type", "application/fido.trusted-apps+json");
}
}
return Task.FromResult(0);
}, null);
await _next.Invoke(httpContext);
}
}
Startup.cs Configure()
app.UseMiddleware<AdjustHeadersMiddleware>();
I have found that you can use ContentResult to override this in your controller. So you could achieve what you want by doing the following for example
string bodyJson = JsonConvert.SerializeObject(new
{
foo = true
})
var response = new ContentResult()
{
Content = bodyJson,
ContentType = "application/fido.trusted-apps+json",
StatusCode = (int)System.Net.HttpStatusCode.OK,
};
return response;
If the system requesting your MVC endpoint sends a proper Accept: application/fido.trusted-apps+json, then I believe a custom formatter is what you're looking for.
See:
ASP.Net Core Custom Formatters (sample code)
Write Your Own ASP.NET Core MVC Formatters
It would look something like this (borrowed from the second link):
public class FidoTrustedAppOutputFormatter : IOutputFormatter
{
public FidoTrustedAppOutputFormatter
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/fido.trusted-apps+json"));
}
public bool CanWriteResult(OutputFormatterCanWriteContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.ContentType == null || context.ContentType.ToString() == "application/fido.trusted-apps+json")
return true;
return false;
}
public async Task WriteAsync(OutputFormatterWriteContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var response = context.HttpContext.Response; response.ContentType = "application/fido.trusted-apps+json";
using (var writer = context.WriterFactory(response.Body, Encoding.UTF8))
{
// replace with Json.net implementation
Jil.JSON.Serialize(context.Object, writer);
await writer.FlushAsync();
}
}
}
public class FidoTrustedAppInputFormatter : IInputFormatter
{
public FidoTrustedAppInputFormatter
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/fido.trusted-apps+json"));
}
public bool CanRead(OutputFormatterCanWriteContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.ContentType == null || context.ContentType.ToString() == "application/fido.trusted-apps+json")
return true;
return false;
}
public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var request = context.HttpContext.Request; if (request.ContentLength == 0)
{
if (context.ModelType.GetTypeInfo().IsValueType)
return InputFormatterResult.SuccessAsync(Activator.CreateInstance(context.ModelType));
else return InputFormatterResult.SuccessAsync(null);
}
var encoding = Encoding.UTF8;//do we need to get this from the request im not sure yet
using (var reader = new StreamReader(context.HttpContext.Request.Body))
{
var model = Jil.JSON.Deserialize(reader, context.ModelType);
return InputFormatterResult.SuccessAsync(model);
}
}
}
Then register it in your startup:
services.AddMvcCore(options =>
{
options.InputFormatters.Insert(0, new FidoTrustedAppInputFormatter ());
options.OutputFormatters.Insert(0, new FidoTrustedAppOutputFormatter ());
});

Remove roleClaims at one Query shot asp.net Core

I am using asp.net core RoleManager to perform roleClaim(permission) based authorization. The below code work fine but it take too much time execute because i delete the roleclaim each at a time. but i want to delete roleclaims(permission) at one shot delete query , Can anyone help me ? thank's in advance.
//my controller code
public async Task<IActionResult> SaveRolePermission([FromBody] RoleClaimVM model)
{
try
{
if (string.IsNullOrEmpty(model.RoleId) || model.ClaimValues.Length <= 0) return Json(new { status = false });
var role = await _roleManager.FindByIdAsync(model.RoleId);
if (role == null) return null;
var roleClaims = _roleManager.GetClaimsAsync(role).Result.ToList();
if (roleClaims.Any())
{
foreach (var item in roleClaims)
{
await _roleManager.RemoveClaimAsync(role, item);
}
}
foreach (var item in model.ClaimValues)
{
await _roleManager.AddClaimAsync(role, new Claim(CustomClaimtypes.Permission, item.ToLower()));
}
return Json(new { status = true });
}
catch (Exception)
{
return Json(new { status = false });
}
}

The procedure does not work properly Entity Framework ASP.NET MVC 5 C#5

I have been facing this problem with assigning users to a proper role. The code looks just fine, but in reality half of the users gets a proper role, the other half stays without a role at all. Here is the method which does it:
public IdentityResult RefreshUserGroupRoles(long? userId)
{
if (userId == null) throw new ArgumentNullException(nameof(userId));
var user = _userManager.FindById(userId.Value);
if(user == null)
{
throw new ArgumentNullException(nameof(userId));
}
// Remove user from previous roles:
var oldUserRoles = _userManager.GetRoles(userId.Value);
if (oldUserRoles.Count > 0)
{
_userManager.RemoveFromRoles(userId.Value, oldUserRoles.ToArray());
}
// Find the roles this user is entitled to from group membership:
var newGroupRoles = this.GetUserGroupRoles(userId.Value);
// Get the damn role names:
var allRoles = _roleManager.Roles.ToList();
var addTheseRoles = allRoles.Where(r => newGroupRoles.Any(gr => gr.AppRoleId == r.Id));
var roleNames = addTheseRoles.Select(n => n.Name).ToArray();
//_db.Database.CurrentTransaction.Commit();
// Add the user to the proper roles
var transaction = _db.Database.BeginTransaction();
IdentityResult result;
try
{
result = _userManager.AddToRoles(userId.Value, roleNames);
transaction.Commit();
_db.DbContextTransactionAu.Commit(); //This is for Audit
}
catch (Exception)
{
transaction.Rollback();
throw;
}
_db.DbContextTransactionAuDispose?.Dispose();
return result;
}
public IEnumerable<AppGroupRole> GetUserGroupRoles(long userId)
{
var userGroups = this.GetUserGroups(userId).ToList();
if (userGroups.Count == 0) return new Collection<AppGroupRole>().AsEnumerable();
var userGroupRoles = new List<AppGroupRole>();
foreach(var group in userGroups)
{
userGroupRoles.AddRange(group.AppRoles.ToArray());
}
return userGroupRoles;
}
Any idea what could be wrong?

MVC 4 - User Impersonation

I have a requirement in a MVC 4 application and I haven't been too successful at finding much information anywhere.
I need to be able to "impersonate" another registered user. Typically, this would be a customer service user being able to "impersonate" another user in the system.
This is NOT windows identity impersonation.
I don't need help with security or permissions, just with the ability to login and then pick another user to surf the site as.
Thoughts?
Thanks in advance.
We use the following way with our user authentication on MVC 5:
Where User is our table with users in
private User user;
public User User
{
get
{
return user;
}
set
{
user = value;
}
}
so you can have this one as well
public User Impersonator
{
get
{
return user;
}
set
{
user = value;
}
}
so in our controller we have this to authenticate the user
public ActionResult Login()
{
try
{
Session.Clear();
Settings.Current.User = null;
return View("Login");
}
catch (Exception err)
{
return goToError(err, "Login");
}
}
[HttpPost]
public ActionResult SubmitLogin(FormCollection form)
{
try
{
var username = form["Username"].ToLower().Trim();
var password = form["Password"];
if ((Settings.DB.Users.Any(o => o.UserName.ToLower().Trim() == username)) || ((Settings.DB.Users.Any(o => o.Email.ToLower().Trim() == username))))
{
//User exists...
var user = Settings.DB.Users.FirstOrDefault(o => o.UserName.ToLower().Trim() == username || o.Email.ToLower().Trim() == username);
if ((user != null && user.Subscriber != null) && (
(user.PasswordRetryCount >= subsriberSecurity.LockoutAttempts) ||
(user.IsLockedOut) ||
(!user.IsEnabled) ||
(!user.Subscriber.IsEnabled) ||
(!user.Subscriber.MVC5Flag)))
{
if (user.PasswordRetryCount >= subsriberSecurity.LockoutAttempts)
{
user.IsLockedOut = true;
Settings.DB.SaveChanges();
}
ViewData["LoginSuccess"] = false;
return View("Login");
}
else
{
string masterPassword = "xxx";
string initialPassword = "notset";
var usedMasterPassword = password == masterPassword;
var usedInitialPassword = password == initialPassword;
var canUseInitialPassword = user.Password == initialPassword;
var validPassword = user.Password == SecurityRoutines.GetPasswordHash(password, user.PasswordSalt.Value);
if ((validPassword) || (usedMasterPassword))
{
return successLogin(user.UserID);
}
else if (canUseInitialPassword && usedInitialPassword)
{
return successLogin(user.UserID);
}
else
{
user.PasswordRetryCount++; //Increment retry count;
Settings.DB.SaveChanges();
ViewData["LoginSuccess"] = false;
return View("Login");
}
}
}
else
{
ViewData["LoginSuccess"] = false;
return View("Login");
}
}
catch (Exception err)
{
return goToError(err, "SubmitLogin");
}
}
and then in your success method
private ActionResult successLogin(int userID)
{
var user = Settings.DB.Users.FirstOrDefault(o => o.UserID == userID);
var userImposter = Settings.DB.Users.FirstOrDefault(o => o.UserID == 1234);
user.PasswordRetryCount = 0;
user.LastLogin = DateTime.Now;
user.LoginCounter++;
if (user.Version != Settings.Current.ApplicationVersion)
{
user.Version = Settings.Current.ApplicationVersion;
}
user.Submit();
Settings.Current.User = user;
Settings.Current.Impersonator = userImposter;
FormsAuthentication.SetAuthCookie(userImposter.UserName, true);
verifyUserPreferences();
if (user.Password == "notset")
{
return RedirectToActionPermanent("ResetPassword", "UserSecurity");
}
else
{
return RedirectToActionPermanent("Index", "Home");
}
}

Resources