Customising ApplicationUser asp.net-identity - c#

I'm trying to add a list of objects the the standard ApplicationUser object in MVC.
I've been looking at dozens of questions all about this but they all seem to be adding a single object, rather than a list.
What I'm trying to do is record all historic passwords a user has used, so I've added a table called AspNetUserPreviousPassword.
In my code I've added this line to the ApplicationUserclass:
public virtual DbSet<AspNetUserPreviousPassword> PreviousUserPasswords { get; set; }
and within the AspNetUserPreviousPassword object I've added the following:
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
I've created the following extensions class:
public static class IdentityExtensions which has appeared in the User.Identity intellisense - so far so good.
{
public static string GetPreviousUserPasswords(this IIdentity identity)
{
var claim = ((ClaimsIdentity)identity).FindFirst("PreviousUserPasswords");
// Test for null to avoid issues during local testing
return (claim != null) ? claim.Value : string.Empty;
}
}
When I went to edit the GenerateUserIdentityAsync function, to insert the custom claims, I began to think my approach was incorrect as you can only add strings, e.g.
userIdentity.AddClaim(new Claim("PreviousUserPasswords", "This must be a string"));
Despite only being able to add a string here, I wanted to test my previous passwords were being read from the database so I added this code to test:
string previousPasswords = "";
await this.PreviousUserPasswords.ForEachAsync(p => previousPasswords += p.PasswordHash);
this.PreviousUserPasswords is always NULL.
My questions:
1) Why is this.PreviousUserPasswords always NULL?
2) Is my approach even correct - can I add a list of objects to ApplicationUser or should I be doing this another way?

Here is the article I used to get preventing the use of previous "X" passwords in my implementation of Asp.Net Identity. I tweaked it to suit my needs but this got me everything I needed to get on the right track. Give it a read.
http://www.c-sharpcorner.com/UploadFile/4b0136/how-to-customize-password-policy-in-Asp-Net-identity/

Related

How to save/pass MongoDB UpdateDefinition for logging and later use?

I am stumped on how to save/pass MongoDB UpdateDefinition for logging and later use
I have created general functions for MongoDB in Azure use on a collection for get, insert, delete, update that work well.
The purpose is to be able to have a standard, pre-configured way to interact with the collection. For update especially, the goal is to be able to flexibly pass in an appropriate UpdateDefinition where that business logic is done elsewhere and passed in.
I can create/update/set/combine the UpdateDefinition itself, but when i try to log it by serializing it, it shows null:
JsonConvert.SerializeObject(updateDef)
When I try to log it, save it to another a class or pass it to another function it displays null:
public class Account
{
[BsonElement("AccountId")]
public int AccountId { get; set; }
[BsonElement("Email")]
public string Email { get; set; }
}
var updateBuilder = Builders<Account>.Update;
var updates = new List<UpdateDefinition<Account>>();
//just using one update here for brevity - purpose is there could be 1:many depending on fields updated
updates.Add(updateBuilder.Set(a => a.Email, email));
//Once all the logic and field update determinations are made
var updateDef = updateBuilder.Combine(updates);
//The updateDef does not serialize to string, it displays null when logging.
_logger.LogInformation("{0} - Update Definition: {1}", actionName, JsonConvert.SerializeObject(updateDef));
//Class Created for passing the Account Update Information for Use by update function
public class AccountUpdateInfo
{
[BsonElement("AccountId")]
public int AccountId { get; set; }
[BsonElement("Update")]
public UpdateDefinition<Account> UpdateDef { get; set; }
}
var acct = new AccountUpdateInfo();
acctInfo.UpdateDef = updateDef
//This also logs a null value for the Update Definition field when the class is serialized.
_logger.LogInformation("{0} - AccountUpdateInfo: {1}", actionName, JsonConvert.SerializeObject(acct));
Any thoughts or ideas on what is happening? I am stumped on why I cannot serialize for logging or pass the value in a class around like I would expect
give this a try:
var json = updateDef.Render(
BsonSerializer.SerializerRegistry.GetSerializer<Account>(),
BsonSerializer.SerializerRegistry)
.AsBsonDocument
.ToString();
and to turn a json string back to an update definition (using implicit operator), you can do:
UpdateDefinition<Account> updateDef = json;
this is off the top of my head and untested. the only thing i'm unsure of (without an IDE) is the .Document.ToString() part above.

parsing object with Property List<Claim> and tell the JsonConvert.DeserializeObject to use specific constructor for claims?

I'm using .NET Core with Newtonsoft.Json. I have a UserModel class that has a List<Claim> property
public class UserModel
{
public string GUID { get; set; }
public bool isActive { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public List<Claim> Claims { get; set; }
}
and I'm trying to parse the JSON request into this object class like so:
public IActionResult Testpost([FromBody]JObject body)
{
if (body == null) return BadRequest();
UserModel user = JsonConvert.DeserializeObject<UserModel>(body.ToString());
return Ok(user);
}
but deserializing JSON into an object like Claim class which I don't have access to throws an exception
Newtonsoft.Json.JsonSerializationException: 'Unable to find a constructor to use for type System.Security.Claims.Claim. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'Claims
because it is not able to decide on a constructor
According to online sources I can create a custom converter class that can manage the UserModel object creation but I would like to avoid this.
Is it possible to deserialize a JSON object into my UserModel class and tell the JsonConvert.DeserializeObject to use a specific Claim constructor like Claim(String, String) for parsing the Claims?
EDIT:
as mentioned by #PaulG i have already check the answer for How to programmatically choose a constructor during deserialization?
however the accepted solution used Creates a new class that implements the JsonConverter class then manually parses the body of the JObject request. Moreover, the answer shows how to deal with Claims but not with complex objects where claims are nested as properties
reading another solution in the thread it shows how to create a class that directly implements the constructor needed like so:
class MyClaim : Claim {
public MyClaim(string type, string value):
base(type, value){}
}
but this will require me to keep note on the difference between Claim and MyClaim when writing my code. the JSON converter may not be able to assume which constructor to use but i should be able to tell it which one. or is it by design and i have to suck it up and write extra code just for this?
because the alternative for me would be something like this:
public IActionResult CreatePublicUser([FromBody]JObject body)
{
string Username = body["Username"].ToString();
string Password = body["Password"].ToString();
var Claims = body["Claims"].Children();
List<Claim> UserClaims = new List<Claim>();
foreach (var c in Claims)
{
UserClaims.Add(
new Claim(
c["Type"].ToString(),
c["Value"].ToString()
)
);
}
UserModel NewUser = (new UserBuilder())
.WithUserName(Username)
.WithPassword(Password)
.WithClaims(UserClaims)
.Build();
return Ok(NewUser)
}
I suggest that you take a different approach altogether which is a common practice as well. Define a model only for the interaction with client, e.g.
public class UserModelWeb
{
public List<ClaimWeb> Claims { get; set; }
}
These DTO objects will be used only for the data conversion from JSON and never in the business logic layer. Then you can map your web models to the business logic that you will be using later. This will allow you to not be dependent on internal classes when you read external data. I.e. if you suddenly add a new field, it will be populated from external (and probably untrusted) source. This clear separation of concerns will not allow this since you will have to explicitly define a field in a web model.
Example for your case: let's say you will have later an internal field in the database that only you can edit: "InternalNote". If you add that field to the model, anyone can post the data and edit the field while your intention was only to allow yourself to edit it.
Additionally this will solve your problem since you won't need to cast to other classes.
P.S. You can use your class directly in action methods:
MyAction([FromBody]UserModelWeb user)
It should be deserialized from json right away.

c# web api request validation filter, context values empty - arguments list isn't

I'm using C# web api and want to create a filter to all requests.
I have a designated class to every request so I just want to add some data annotations and get the validation over with.
The problem is that I'm getting true every time on actionContext.ModelState.IsValid
I have added my filter in the config:
config.Filters.Add(new RequestValidationFilter());
validation method looks like every other in the web
public class RequestValidationFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
var errors = actionContext.ModelState
.Values
.SelectMany(m => m.Errors
.Select(e => e.ErrorMessage));
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
actionContext.Response.ReasonPhrase = string.Join("\n", errors);
}
}
}
I have the following method:
[HttpPost, Route("User/Login")]
public async Task<Responses.Login> Login(Requests.Login request)
{
...//some login logic
}
And also, I have my model which is:
public class Requests
{
public class Login
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Email address cannot be empty!")]
[MinLength(5)]
public string Email;
[Required]
public string Password;
}
}
I'm sending both an empty request or request which Email and Password are null and still the actionContext.ModelState.IsValid evaluate it as true
Attached is an image when email was sent but password wasn't.
Following a comment, here is my request via Advanced Rest Client chrome plugin
NOTE
the image actually shows that Keys and Values are empty when in fact they are supplied..
EDIT
number of things i've also tried:
removing all other filters, why? maybe the context was messed up by another reading.
sending valid request in terms of fields, but email was 1 char long.why? maybe Requiredis working differently than others, still nothing about the min-length issue.
instead of nested objects, i created a seperate stand-alone class for the Login object. why? thought maybe the fact that it's nested the validation is not recursive.
Looping the Arguments list one-by-one and validate as object, answer is always true. never fails, why? cause Im almost admitting defeat.
instead of adding filter to config as i described in the question, tried GlobalConfiguration.Configuration.Filters.Add(new RequestValidationFilter()); instead
You need to add { get; set; } after your model properties:
public class Login
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Email address cannot be empty!")]
[MinLength(5)]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
This is necessary because the default model validation for ASP.NET only includes properties with a public get method. From PropertyHelper.cs, here's some of the code which determines whether a property on the model will be included in validation:
// Indexed properties are not useful (or valid) for grabbing properties off an object.
private static bool IsInterestingProperty(PropertyInfo property)
{
return property.GetIndexParameters().Length == 0 &&
property.GetMethod != null &&
property.GetMethod.IsPublic &&
!property.GetMethod.IsStatic;
}
This method is used to filter the properties that are used in the default model binding in MVC/Web API. Notice that it's checking whether the GetMethod exists on the property and that it's public. Since your class didn't have the get methods on its properties, they were being ignored.
If you want to know more, you can kill a lot of time looking through the ASP.NET MVC source. I think the code on github is for a newer version of ASP.NET, but it seems like a lot of the same logic applies in the version you are using.

ASP.NET Identity - extending the _LoginPartial

I'm finding this difficult to summarise, hence the poor question name. On my .net web application, which is using Identity, there is a login partial that was auto generated that displays the users 'username' property like so:
#Html.ActionLink(User.Identity.GetUserName(), "Index", "Manage", routeValues: null, htmlAttributes: new {title = "Manage"})
After profiling the SQL database that is holding the user data, I noticed that this call to GetUserName() doesn't actually make a call to the database to retrieve the name. I am looking to access a navigation property of the 'ApplicationUser' class that holds the url for a thumbnail image I want to be displayed.
However I am hoping I can achieve this without the need to call the database for the URL on every page request. An example of this would be on this site, where your profile image is displayed on every page as part of the layout.
The application user class has this property.
public class ApplicationUser : IdentityUser
{
public UserProfile Profile { get; set; }
}
And the user profile class holds this property.
public class UserProfile
{
[Key, ForeignKey("User")]
public string UserId { get; set; }
public ApplicationUser User { get; set; }
[Required]
public string ThumbnailUrl { get; set; }
...
}
How can I do this? Or is there a much better way of trying to achieve this.
You can just add them as claims.
When authenticating you should fetch the User from the DB and add all the properties you would need use later on.
Assuming that you are using CreateIdentity when logging in a user, that should return a ClaimsIdentity object.
var userIdentity = await userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
userIdentity.AddClaim(new Claim("Thumbnail", user.ThumbnailUrl));
Then you need to create a extension class, let's say IdentityExtensions:
public static class IdentityExtensions{
public static string Thumbnail(this IIdentity identity){
try{
return ((ClaimsIdentity) identity).FindFirst("Thumbnail").Value;
}
catch(Exception ex){
// handle any exception the way you need
}
}
}
Finally, on your views you should be able to use #User.Identity.Thumbnail()
You're right it doesn't make a call... the reason is because it's holding that data in the client's cookies... If it didn't the server would have a meltdown if it had to keep running back and forth to grab such trivial data for large scale systems... so it's cached.
The way it's done in ASP.NET MVC is via the use of the IPrinciple interface... I'll point you in the right direction to learn more about it...
CodeProject: How to implement a custom IPrincipal in MVC
Best thing todo is to create a second table (or add a column to the current table), add a file upload feature to the registration form. When registration is successful add the picture to the db with EntityFramework. Create a page to return the picture by the userid so you can include it in a page somewhere.
you can use this idea
http://blogs.msdn.com/b/webdev/archive/2013/10/16/customizing-profile-information-in-asp-net-identity-in-vs-2013-templates.aspx

Best way to do property level authorization in ServiceStack?

I'm currently developing a SPA in Angular, and so I've created a REST service using ServiceStack. I am also using ServiceStack's default authentication and authorization solution, which allows me to decorate services with the Authenticate attribute, and also allows me to authorize roles.
However, since my application has users, and users own resources, I need a way to restrict non-authorized users from performing certain actions. Furthermore, I would like to be able to create a single service for each discrete entity which can properly figure out what is safe to write to the database and what is safe to return to the user depending on their level of authorization.
So as an example, let's say I've created a service to handle operations on a Group entity. One of the actions I allow on a Group is to get the details for it:
Route: api/groups/{Id}
Response: Name, Description, CoverImageUrl, Members
However, depending on who the user is, I wish to restrict what data is returned:
Not authenticated: Name, CoverImageUrl
Authenticated: Name, CoverImageUrl, Decription
Member of requested group: Full access
Admin of website: Full access
So one simple approach to doing this is to create 3 different response DTOs, one for each type of response. Then in the service itself I can check who the user is, check on their relation to the resource, and return the appropriate response. The problem with this approach is that I would be repeating myself a lot, and would be creating DTOs that are simply subsets of the "master" DTO.
For me, the ideal solution would be some way to decorate each property on the DTO with attributes like:
[CanRead("Admin", "Owner", "Member")]
[CanWrite("Admin", "Owner")]
Then somewhere during the request, it would limit what is written to the database based on who the user is and would only serialize the subset of the "master" DTO that the user is permitted to read.
Does anyone know how I can attain my ideal solution within ServiceStack, or perhaps something even better?
The direct approach is the easiest, but you could also take advantage of custom filters attributes.
[Route("/groups/{Id}"]
public class UpdateGroup
{
public int Id { get; set; }
public string Name { get; set; }
public string CoverImageUrl { get; set; }
public string Description { get; set; }
}
[RequiresAnyRole("Admin", "FullAccess")]
[Route("/admin/groups/{Id}"]
public class AdminUpdateGroup
{
public int Id { get; set; }
public string Name { get; set; }
public string CoverImageUrl { get; set; }
public string Description { get; set; }
//... other admin properties
}
Service implementation:
public object Any(UpdateGroup request)
{
var session = base.SessionAs<AuthUserSession>();
if (session.IsAuthenticated) {
//.. update Name, CoverImageUrl, Description
}
else {
//.. only update Name, CoverImageUrl
}
}
public object Any(AdminUpdateGroup request)
{
//... Full Access
}
What ended up being the most pragmatic solution for me was actually pretty simple. The basic idea is that whichever service requires row-level authorization should implement a GetUserRole method, which in my case returns the user's most permissive role.
protected string GetUserRole(Domain.Group entity)
{
var session = SessionAs<AuthUserSession>();
var username = session.UserName;
if (session.Roles.Contains("Admin"))
{
return "Admin";
}
if (entity.Id == default(int) || entity.Leader.Username.Equals(username))
{
return "Leader";
}
// More logic here...
return session.IsAuthenticated ? "User" : "Anonymous";
}
Then I can use the user's role to figure out what to let them write:
var entityToWriteTo = ... // code that gets your entity
var userRole = GetUserRole(entityToWriteTo);
if (new[] {"Admin"}.Contains(userRole))
{
// write to admin-only entity properties
}
if (new[] {"Admin", "Leader"}.Contains(userRole))
{
// write to admin or leader entity properties
}
// Etc.
And the same logic applies for reads: You populate a DTO with properties set conditionally based on their role. Later on when you return the DTO back to the client, any properties that you haven't set either won't be serialized or will be serialized with a null value.
Ultimately, this solution allows you to use a single service for a resource instead of creating multiple services each with their own request DTO. There are, of course, refactorings you can do that makes this solution more streamlined. For example, you can isolate all of your reads and writes to one part of your code which will keep the services themselves free of role checks and things like that.

Categories