What is the burden of User.Identity.GetUserId()? - asp.net-mvc

In my ASP.NET MVC applications I use User.Identity.GetUserId() abundantly. However, I wonder if this has severe performance penalties.
Alternatively, I believe I can do this: In a View, I can assign the current user's id to a hidden field in the first page load. Then, when making AJAX calls, I can pass the hidden field value to controllers' actions. This way, I would not need to use User.Identity.GetUserId() method to retrieve the userid of the current user.
I wonder if anyone has any ideas on this?

Take a look at the source for GetUserId extension method:
/// <summary>
/// Return the user id using the UserIdClaimType
/// </summary>
/// <param name="identity"></param>
/// <returns></returns>
public static string GetUserId(this IIdentity identity)
{
if (identity == null)
{
throw new ArgumentNullException("identity");
}
var ci = identity as ClaimsIdentity;
if (ci != null)
{
return ci.FindFirstValue(ClaimTypes.NameIdentifier);
}
return null;
}
/// <summary>
/// Return the claim value for the first claim with the specified type if it exists, null otherwise
/// </summary>
/// <param name="identity"></param>
/// <param name="claimType"></param>
/// <returns></returns>
public static string FindFirstValue(this ClaimsIdentity identity, string claimType)
{
if (identity == null)
{
throw new ArgumentNullException("identity");
}
var claim = identity.FindFirst(claimType);
return claim != null ? claim.Value : null;
}
Every time you call that extension method it searches the identity for the ClaimTypes.NameIdentifier claim.
The performance impact is not that substantial (IMO) but leaking user information in hidden (there not actually hidden if one can see them with one click of view source) is not a good idea.
If you are concerned about calling it multiple times and need it in multiple locations through out a request then you can have it lazy loaded behind a property in your controller or a base controller.
private string userId
public string UserId {
get {
if(userid == null) {
userid = User.Identity.GetUserId();
}
return userid;
}
}
You could also create a service to encapsulate that information.

Related

PlannerTaskDetail's GetETag returns null. If-Match header not working

I'm trying to update task details:
var t = await graphClient.Planner.Tasks[task.Id].Details.Request().GetAsync();
var ETag = t.GetETag();
However GetETag() returns null.
The ETag is part of the AdditionalData dictionary, so I can extract it writing my own method.
For example:
var e = etag = (taskDetails.AdditionalData["#odata.etag"] as JsonElement?)?.GetString();
But why does the built-in method not work? My code is almost exactly the same as Microsoft's test code.
Thanks.
Please debug and check GetEtag() method that is exposed here. Also validate the entity passed onto this method is not null.
namespace Microsoft.Graph
{
using System;
/// <summary>
/// Helper class to extract #odata.etag property and to specify If-Match headers for requests.
/// </summary>
public static class EtagHelper
{
/// <summary>
/// Name of the OData etag property.
/// </summary>
public const string ODataEtagPropertyName = "#odata.etag";
/// <summary>
/// Returns the etag of an entity.
/// </summary>
/// <param name="entity">The entity that contains an etag.</param>
/// <returns>Etag value if present, null otherwise.</returns>
public static string GetEtag(this Entity entity)
{
if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
entity.AdditionalData.TryGetValue(ODataEtagPropertyName, out object etag);
return etag as string;
}
}
}

Custom dynamic dataannotation for field visibility c#

I am trying to create a dataannotations attribute that controls field visiblity based on settings in a database. The attribute will be used within a system that will be used by multiple clients. Further, the visibility of the field needs to be able to change on the fly. I know I could do an if statement around each field in the view, but I am trying to avoid that and keep the visibility control within the view model as follows:
[Visible(FirstName)]
public string FirstName { get; set; }
I have tried creating this custom attribute that gets the value from a method from a resource class called ResourceType (which is generated using T4 and contains the necessary code to hit the database):
public class VisibleAttribute : Attribute, IMetadataAware
{
/// <summary>
/// Whether this field is visible
/// </summary>
public bool Hidden { get; set; }
public VisibleAttribute(string theFieldName)
{
ResourceType resources = new ResourceType();
Type _resourceType = typeof(ResourceType);
MethodInfo getHidden = _resourceType.GetMethod("IsHidden");
object[] requiredParams = new object[] { theFieldName };
Hidden = (bool)getHidden.Invoke(resources, requiredParams);
}
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.ShowForEdit = !Hidden;
metadata.HideSurroundingHtml = Hidden;
}
}
Here is an excerpt of the ResourceType class:
public class ResourceType
{
public const string Creditors_SecondaryCreditorsPayOffYesNo_Require = "Prop_Creditors_SecondaryCreditorsPayOffYesNo_Require";
public static string Prop_FieldName_Require
{
get { return GetHiddenOption(FieldName) ? "true" : "false"; }
}
internal static bool GetHiddenOption(string fieldName)
{
< < Logic here to get the option from the database > >
}
I have also tried the same attribute but with the following constructor:
public VisibleAttribute(string theFieldName)
{
ResourceType resources = new ResourceType();
Type _resourceType = typeof(ResourceType);
PropertyInfo getHidden = _resourceType.GetProperty(theFieldName);
Hidden = (bool)getHidden.GetValue
}
The problem I have with these two attempts is that, since the code is in the constructor, it only runs the first time I load the page after an IIS reset. So, any further changes I make to the visibility settings are not reflected without amother IIS reset.
I also tried creating a custom DataAnnotationsModelMetadataProvider that attempts to only load the setting once per page request:
public class EGTDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
Func<object> modelAccessor, Type modelType, string propertyName)
{
var data = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var visibleAttributeMetadata = attributes.SingleOrDefault(a => typeof(VisibleAttribute) == a.GetType());
if (visibleAttributeMetadata != null)
{
VisibleAttribute visibleAttribte = (VisibleAttribute)visibleAttributeMetadata;
if (!visibleAttribte.VisibleIsSet)
{
PropertyInfo getHidden = visibleAttribte.ResourceType.GetProperty("Prop_" + WebUtils.RemoveSectionNameSpace(visibleAttribte.SectionName) + "_" + visibleAttribte.FieldName + "_Hide");
visibleAttribte.IsHidden = bool.Parse(getHidden.GetValue(null, null).ToString());
data.HideSurroundingHtml = visibleAttribte.IsHidden;
data.ShowForEdit = !visibleAttribte.IsHidden;
visibleAttribte.VisibleIsSet = true;
}
else
{
data.HideSurroundingHtml = visibleAttribte.IsHidden;
data.ShowForEdit = !visibleAttribte.IsHidden;
}
}
return data;
}
}
One issue I have with the ModelMetadataProvider is that the CreateMetadata method runs many times for a single field during a single request. It is very inefficient code, and a huge decrease in performace, to call the database 5-10+ times per request to get a setting that has not changed since the beginning of the request. If I try to set a flag indicating I've already loaded the setting, I'm back to the same scenario as above where I don't see the setting change until after an IIS reset.
I'm hoping someone can give me some pointers as to what methods I can employ to see the database changes real time. Or am I trying to do the impossible? Thanks in advance.
You could combine the metadata provider approach with caching the value just that single request.
For this you could use the Items dictionary in the current HttpContext. Be careful with this as a redirect will cause the items to be cleared:
string cacheKey = String.Format("IsVisible-{0}", propertyName)
if(!HttpContext.Current.Items.Contains(cacheKey))
HttpContext.Current.Items[cacheKey] = //get setting from db
bool isVisible = (bool)HttpContext.Current.Items[cacheKey];
You can also consider using the ASP .Net Cache in case that you prefer caching the value not just for the current request (Although you mentioned that within your metadata provider you were trying to load the setting once per request)

Using MvcContrib TestHelper to assert that an inbound route should not be mapped

Looked for a method on the MvcContrib.TestHelper.RouteTestingExtensions class named ShouldNotMap. There is ShouldBeIgnored, but I don't want to test an IgnoreRoute invocation. I want to test that a specific incoming route should not be mapped to any resource.
Is there a way to do this using MvcContrib TestHelper?
Update
Just tried this, and it seems to work. Is this the correct way?
"~/do/not/map/this".Route().ShouldBeNull();
I think you are looking for the following:
"~/do/not/map/this".ShouldBeIgnored();
Behind the scenes this asserts that the route is processed by StopRoutingHandler.
I was looking for the same thing. I ended up adding the following extension methods to implement ShouldBeNull and the even shorter ShouldNotMap:
In RouteTestingExtensions.cs:
/// <summary>
/// Verifies that no corresponding route is defined.
/// </summary>
/// <param name="relativeUrl"></param>
public static void ShouldNotMap(this string relativeUrl)
{
RouteData routeData = relativeUrl.Route();
routeData.ShouldBeNull(string.Format("URL '{0}' shouldn't map.", relativeUrl));
}
/// <summary>
/// Verifies that the <see cref="RouteData">routeData</see> is null.
/// </summary>
public static void ShouldNotMap(this RouteData routeData)
{
routeData.ShouldBeNull("URL should not map.");
}
In GeneralTestExtensions.cs :
///<summary>
/// Asserts that the object should be null.
///</summary>
///<param name="actual"></param>
///<param name="message"></param>
///<exception cref="AssertFailedException"></exception>
public static void ShouldBeNull(this object actual, string message)
{
if (actual != null)
{
throw new AssertFailedException(message);
}
}

ASP.NET MVC 3 app, BCrypt.CheckPassword failing

I'm working on implementing security in an ASP.NET MVC 3 application, and am using the BCrypt implementation found here to handle encryption and verification of passwords. The user registration screen encrypts the password the user provides just fine, and the hashed password gets saved to the database. I'm having a problem with password verification on the login page though, and I can't seem to figure out why.
My registration controller action contains the following:
[HttpPost]
[RequireHttps]
public ActionResult Register(Registration registration)
{
// Validation logic...
try
{
var user = new User
{
Username = registration.Username,
Password = Password.Hash(HttpUtility.HtmlDecode(registration.Password)),
EmailAddress = registration.EmailAddress,
FirstName = registration.FirstName,
MiddleInitial = registration.MiddleInitial,
LastName = registration.LastName,
DateCreated = DateTime.Now,
DateModified = DateTime.Now,
LastLogin = DateTime.Now
};
var userId = _repository.CreateUser(user);
}
catch (Exception ex)
{
ModelState.AddModelError("User", "Error creating user, please try again.");
return View(registration);
}
// Do some other stuff...
}
This is Password.Hash:
public static string Hash(string password)
{
return BCrypt.HashPassword(password, BCrypt.GenerateSalt(12));
}
This is how I'm handling login:
[HttpPost]
[RequireHttps]
public ActionResult Login(Credentials login)
{
// Validation logic...
var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), login.password);
if (authorized)
{
// log the user in...
}
else
{
ModelState.AddModelError("AuthFail", "Authentication failed, please try again");
return View(login);
}
}
CredentialsAreValid wraps the call to BCrypt.CheckPassword:
public bool CredentialsAreValid(string username, string password)
{
var user = GetUser(username);
if (user == null)
return false;
return Password.Compare(password, user.Password);
}
Password.Compare:
public static bool Compare(string password, string hash)
{
return BCrypt.CheckPassword(password, hash);
}
And finally, this is what BCrypt.CheckPassword is doing:
public static bool CheckPassword(string plaintext, string hashed)
{
return StringComparer.Ordinal.Compare(hashed, HashPassword(plaintext, hashed)) == 0;
}
So, yeah...I dunno what's going on, but what I do know, is that my boolean authorized variable in my Login controller action always returns false for some reason.
I've used this exact same BCrypt class on at least a couple of other projects in the past, and never had any problems with it at all. Is ASP.NET MVC 3 doing some weird, different encoding to posted data that I'm missing or need to handle differently or something? Either that, or is SQL CE 4 doing it (that's the datastore I'm currently using)? Everything seems to be in order in my code from what I can tell, but for some reason, password checking is failing every time. Anyone have any ideas?
Thanks.
UPDATE: Here's the code comments included with the BCrypt class with examples of how it's used and works.
/// <summary>BCrypt implements OpenBSD-style Blowfish password hashing
/// using the scheme described in "A Future-Adaptable Password Scheme"
/// by Niels Provos and David Mazieres.</summary>
/// <remarks>
/// <para>This password hashing system tries to thwart offline
/// password cracking using a computationally-intensive hashing
/// algorithm, based on Bruce Schneier's Blowfish cipher. The work
/// factor of the algorithm is parametized, so it can be increased as
/// computers get faster.</para>
/// <para>To hash a password for the first time, call the
/// <c>HashPassword</c> method with a random salt, like this:</para>
/// <code>
/// string hashed = BCrypt.HashPassword(plainPassword, BCrypt.GenerateSalt());
/// </code>
/// <para>To check whether a plaintext password matches one that has
/// been hashed previously, use the <c>CheckPassword</c> method:</para>
/// <code>
/// if (BCrypt.CheckPassword(candidatePassword, storedHash)) {
/// Console.WriteLine("It matches");
/// } else {
/// Console.WriteLine("It does not match");
/// }
/// </code>
/// <para>The <c>GenerateSalt</c> method takes an optional parameter
/// (logRounds) that determines the computational complexity of the
/// hashing:</para>
/// <code>
/// string strongSalt = BCrypt.GenerateSalt(10);
/// string strongerSalt = BCrypt.GenerateSalt(12);
/// </code>
/// <para>
/// The amount of work increases exponentially (2**log_rounds), so
/// each increment is twice as much work. The default log_rounds is
/// 10, and the valid range is 4 to 31.
/// </para>
/// </remarks>
Forgive me if I'm missing something, but looking at your hash and your model you don't seem to store the salt anywhere, instead you use a new salt each time.
So when the password is set you must store both the hash and the salt; when you want to check an entered password you retrieve the salt, compute the hash using it, then compare against the stored one.
I had the same problem. BCryptHelper.CheckPassword always returns false
I found that the the hashed string was stored in the db as a nchar(). This caused the check to always fail.
I changed this to char() and it works.
HttpUtility.HtmlDecode() is used when the user is created, before the password is originally hashed:
Password = Password.Hash(HttpUtility.HtmlDecode(registration.Password)),
However, HttpUtility.HtmlDecode() is not used when later when comparing password to hash, in
var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), login.password);
Perhaps a slight change to:
var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), HttpUtility.HtmlDecode(login.password));
I realize this is an older question but I'm contemplating using BCrypt and this question raised a potential flag for me so I'm interested in knowing if this resolves this issue. I apologize, I'm not in a position at the moment to verify my answer, but I hope it helps.

FilePathResult or custom Action Result?

To send pdf files (or any other file type) to the browser, I've seen examples that use the FileResult class or a custom Action Result.
Is there an advantage of using one over the other? Thanks
EDIT Original reply removed.
I'm not sure if the exist file result allows to you modify the content disposition, I believe it forces the content disposition of "attachment". If you want to use a different disposition, I'd implement a custom Action Filter:
/// <summary>
/// Defines an <see cref="ActionResult" /> that allows the output of an inline file.
/// </summary>
public class InlineFileResult : FileContentResult
{
#region Constructors
/// <summary>
/// Writes the binary content as an inline file.
/// </summary>
/// <param name="data">The data to be written to the output stream.</param>
/// <param name="contentType">The content type of the data.</param>
/// <param name="fileName">The filename of the inline file.</param>
public InlineFileResult(byte[] data, string contentType, string fileName)
: base(data, contentType)
{
FileDownloadName = fileName;
}
#endregion
#region Methods
/// <summary>
/// Executes the result, by writing the contents of the file to the output stream.
/// </summary>
/// <param name="context">The context of the controller.</param>
public override void ExecuteResult(ControllerContext context)
{
if (context == null) {
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = this.ContentType;
if (!string.IsNullOrEmpty(this.FileDownloadName)) {
ContentDisposition disposition = new ContentDisposition();
disposition.FileName = FileDownloadName;
disposition.Inline = true;
context.HttpContext.Response.AddHeader("Content-Disposition", disposition.ToString());
}
WriteFile(response);
}
#endregion
}
That is one I've used previously, because I pass the actual byte[] data of the file.
They would essentially do the same thing. Setting up a FileContentResult is probably the most straight-forward and easiest to get started with:
public FileContentResult GetPdf()
{
return File(/* byte array contents */, "application/pdf");
}
If you wanted to save yourself from having to specify the content type (if you are always going to do PDF), you could create an ActionResult that specified the content type (application/pdf) inside of it, and return that instead of the FileContentResult (maybe something like PdfContentResult).
But like I said, they will do the same thing and there will not be any performance difference.

Resources