Where to set MembershipPassword() requirments? - asp.net-mvc-5

The selected answer here shows one method of how the requirments can be set but I am looking to make those rules more reusable while still using the MembeshipPassowrd() validation attribute and I think it can be done by specifying the roles within my extended membership provider but I can't find any documentation on how this can be done.
How do I include the password requirments within my custom/extended membership provider?
Model
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[MembershipPassword(
MinRequiredNonAlphanumericCharacters = 1,
MinNonAlphanumericCharactersError = "Your password needs to contain at least one symbol (!, #, #, etc).",
ErrorMessage = "Your password must be 6 characters long and contain at least one symbol (!, #, #, etc)."
)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }

Seems like the PasswordStrngthRegularExpression is what is required to do this, it can either be set in the web.config file or within the extended membership provider by overriding it:
public override string PasswordStrengthRegularExpression
{
get { return #"(?=.{5,})(?=(.*\d){1,})(?=(.*\W){1,})(?=.*[a-z])(?=.*[A-Z])"; }
}
OR
<membership defaultProvider="SqlProvider"
userIsOnlineTimeWindow = "20>
<providers>
<add
name="SqlProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="SqlServices"
requiresQuestionAndAnswer="true"
passwordStrengthRegularExpression="#\"(?=.{6,})(?=(.*\d){1,})(?=(.*\W){1,})"
/>
</providers>
</membership>
MSDN Has details on this.

Related

Creating A Per-View Resource File In MVC

I am converting a localized WebForms application to MVC5. Most of the examples I have seen for MVC have a single resource - resx - file (per language) for the entire application.
Is it possible, to have a separate file for each view? If so, is there an example of how to reference the said file?
UPDATE: I would like to leave the resource files uncompiled if possible. This would allow us to edit the RESX files on the fly without having to recompile the site everytime.
Below is the procedure I had in WebForms. I am essentially trying to reproduce this in MVC5.
public string LocalizeText(Page CurrentPage, string resourceKey)
{
string localizedText = string.Empty;
// LOOK FOR LOCALIZED TEXT
String filePath = string.Empty;
if (!String.IsNullOrEmpty(CurrentPage.Request.GetFriendlyUrlFileVirtualPath()))
{
filePath = CurrentPage.Request.GetFriendlyUrlFileVirtualPath(); // FOR FRIENDLY URLS
}
else
{
filePath = CurrentPage.Request.CurrentExecutionFilePath; // FOR "UNFRIENDLY" URLS (THOSE WITH A FILE EXTENSION VISIBLE)
}
try
{
localizedText = Convert.ToString(HttpContext.GetLocalResourceObject(filePath, resourceKey, System.Globalization.CultureInfo.CurrentCulture)).Trim();
}
catch (Exception ex)
{
HttpContext.Current.Response.Write(ex.ToString() + "<br />" + filePath);
}
return localizedText;
}
The resource files would be located in the App_LocalResources folder.
Yes, it is possible to have a separate resource file for a view. As a really simple, and pretty dull example (sorry about that :-)), consider the following view model:
using _31662592.Resources;
using System.ComponentModel.DataAnnotations;
public class HomeViewModel
{
[Display(Name = "WelcomeHeader", ResourceType = typeof(HomeResources))]
public string WelcomeHeader { get; set; }
[Display(Name = "WelcomeMessage", ResourceType = typeof(HomeResources))]
public string WelcomeMessage { get; set; }
}
Here, I'm making use of the Display attribute, which has support for localisation. So in my case, the resource file I created looks like this:
As you can see, the ResourceType property corresponds with the type of your resource file (i.e. HomeResources in my case), and the Name property corresponds with the name of the string in the resource file which you wish to bind the property to.
Nothing fancy in the action:
public ActionResult Index()
{
return View(new HomeViewModel());
}
The view is very simple too:
#model _31662592.Models.HomeViewModel
<h1>#Html.DisplayNameFor(m => m.WelcomeHeader)</h1>
<p>#Html.DisplayNameFor(m => m.WelcomeMessage)</p>
You can even use the resources inline in your views, such as:
#using _31662592.Resources
<h1>#HomeResources.WelcomeHeader</h1>
<p>#HomeResources.WelcomeMessage</p>
In case you have any problems, you should make sure that:
The Build Action for the resource is set to "Embedded Resource".
The Custom Tool for the resource is set to "PublicResXFileCodeGenerator".
Both of these options can be set by right-clicking on the resource file and selecting Properties. Those options will then be shown in the properties dockable window. Finally, if you wish to reference the resource file from another project, make sure it's set to Public rather than internal, which you can set by double-clicking the resource file to open it as normal, then changing its access modifier from internal to public.

Sudden 'No valid key mapping found for securityToken' error

TL;DR
Our website suddenly had the below error with no code or web.config changes. Would Azure have changed?
I have a website which has been running on Azure with no issues for a few months. Then the other day, we now have this error:
WIF10201: No valid key mapping found for securityToken: 'System.IdentityModel.Tokens.X509SecurityToken' and issuer: 'https://sts.windows.net/<guid>/'.
We have made no changes to the web.config or the values in Tenants and IssuingAuthorityKeys.
Searching SO and the web give lots of code based answers, but we haven't changed any code.
The web.config is like this:
<system.identityModel>
<identityConfiguration>
<issuerNameRegistry type="DatabaseIssuerNameRegistry, Site.Web" />
<audienceUris>
<add value="https://localhost:44301" />
<add value="https://<other urls...>" />
</audienceUris>
<securityTokenHandlers>
<add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</securityTokenHandlers>
<certificateValidation certificateValidationMode="None" />
</identityConfiguration>
</system.identityModel>
The issuerNameRegistry class is as follows:
public class DatabaseIssuerNameRegistry : ValidatingIssuerNameRegistry
{
public static bool ContainsTenant(string tenantId)
{
using (DBEntities context = new DBEntities())
{
return context.Tenants
.Where(tenant => tenant.Id == tenantId)
.Any();
}
}
public static bool ContainsKey(string thumbprint)
{
using (DBEntities context = new DBEntities())
{
return context.IssuingAuthorityKeys
.Where(key => key.Id == thumbprint)
.Any();
}
}
public static void RefreshKeys(string metadataLocation)
{
IssuingAuthority issuingAuthority = ValidatingIssuerNameRegistry.GetIssuingAuthority(metadataLocation);
bool newKeys = false;
bool refreshTenant = false;
foreach (string thumbprint in issuingAuthority.Thumbprints)
{
if (!ContainsKey(thumbprint))
{
newKeys = true;
refreshTenant = true;
break;
}
}
foreach (string issuer in issuingAuthority.Issuers)
{
if (!ContainsTenant(GetIssuerId(issuer)))
{
refreshTenant = true;
break;
}
}
if (newKeys || refreshTenant)
{
using (DBEntities context = new DBEntities())
{
if (newKeys)
{
context.IssuingAuthorityKeys.RemoveRange(context.IssuingAuthorityKeys);
foreach (string thumbprint in issuingAuthority.Thumbprints)
{
context.IssuingAuthorityKeys.Add(new IssuingAuthorityKey { Id = thumbprint });
}
}
if (refreshTenant)
{
foreach (string issuer in issuingAuthority.Issuers)
{
string issuerId = GetIssuerId(issuer);
if (!ContainsTenant(issuerId))
{
context.Tenants.Add(new Tenant { Id = issuerId });
}
}
}
context.SaveChanges();
}
}
}
private static string GetIssuerId(string issuer)
{
return issuer.TrimEnd('/').Split('/').Last();
}
protected override bool IsThumbprintValid(string thumbprint, string issuer)
{
return ContainsTenant(GetIssuerId(issuer))
&& ContainsKey(thumbprint);
}
}
Judging from this Technet article, it seems that Microsoft may have updated the way they handle Tenant keys.
I had to add the following code into my Global.asax.cs file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
// ....
string configPath = AppDomain.CurrentDomain.BaseDirectory + "\\" + "Web.config";
string metadataAddress =
ConfigurationManager.AppSettings["ida:FederationMetadataLocation"];
ValidatingIssuerNameRegistry.WriteToConfig(metadataAddress, configPath);
}
Check out my answer on a similar post. It only applies to solutions created in VS2013 or later.
https://stackoverflow.com/a/38131092/5919316
Here is a copy of it:
For solutions created in VS2013 and later, the solution should contain the logic to roll over keys automatically. No need to put the value in the web.config file.
You might run into this issue when migrating your solution from local to another environment. In that case you will probably try to point your solution to a new application in Azure Active Directory. Check the following:
Make sure all urls in the web.config are pointing to the correct url not the one automatically generated when you set it up locally
Remove all enteries from IssuingAuthorityKeys table. The keys will autopopulate when you re-build the solution and run it. On the server you might need to replace the dlls manually for it to refresh
Last and most important, delete all rows from the Tenants table. On the first run on the new environment, an Admin from the owning Active Directory has to sign up and authorize the application.
If the values in both tables are still not populated automatically after these steps, check this article for steps on how to manually get the values.

context error- The entity type ApplicationUser is not part of the model for the current context

Well, I have tried many things without any help.
The situation is if I have my connection string as a regular connection string for example:
<add name="MyConnectionString" connectionString="Data Source=mydatasource;Connection Lifetime=10;Max Pool Size=800;Initial Catalog=mydb;Persist Security Info=True;MultipleActiveResultSets=True;User ID=myuser;Password=mypass" providerName="System.Data.SqlClient" />
I have this error:
The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. To fix this problem do not remove the line of code that throws this exception. If you wish to use Database First or Model First, then make sure that the Entity Framework connection string is included in the app.config or web.config of the start-up project. If you are creating your own DbConnection, then make sure that it is an EntityConnection and not some other type of DbConnection, and that you pass it to one of the base DbContext constructors that take a DbConnection. To learn more about Code First, Database First, and Model First see the Entity Framework documentation here: http://go.microsoft.com/fwlink/?LinkId=394715
and the error comes from here:
public partial class myConnectionString : DbContext
{
public myConnectionString()
: base("name=myConnectionString")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();// error comes from here
}
public virtual DbSet<AspNetRoles> AspNetRoles { get; set; }
public virtual DbSet<AspNetUserClaims> AspNetUserClaims { get; set; }
public virtual DbSet<AspNetUserLogins> AspNetUserLogins { get; set; }
public virtual DbSet<AspNetUsers> AspNetUsers { get; set; }
public virtual DbSet<ConnectedUsers> ConnectedUsers { get; set; }
}
If I have the EF connection string. for example:
<add name="myConnectionString" connectionString="metadata=res://*/HdkDb.csdl|res://*/HdkDb.ssdl|res://*/HdkDb.msl;provider=System.Data.SqlClient;provider connection string="data source=mydatasource;initial catalog=mydb;user id=myuser;password=mypass;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
I have this error:
The entity type ApplicationUser is not part of the model for the current context.
and the error comes from here:
var user = UserManager.Find(email, password);
this is what I have in my startup.auth.cs
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}
Things to be noted:
I have Entity framework (EDMX) in one project, Authentication (IdentityModel, Usermanager) in another project. And I have using it from another MVC 5 project(where I have the startup.auth.cs).
In all of the projects app/web config, I have the same connection string.
How would I solve this? any help !!

Instantiation of POCO objects with ServiceStack's IAppSettings is not working

I have registered AppSettings within my AppHost as shown below:
container.Register<IAppSettings>(new AppSettings());
I have added following settings within my web.config file:
<appSettings>
<add key="baseaddress" value="http://example.com" />
<add key="credential" value="{Username:foo,Password:bar}" />
</appSettings>
That's my service:
public class ExampleService : Service
{
public IAppSettings Settings { get; set; }
public void Post(ExampleRequest request)
{
// NOT WORKING -> always NULL!
var credentials = Settings.Get<Credential>("credential", null);
// OK
var baseUrl = Settings.GetString("baseaddress");
// more code...
}
}
This is my Credential class:
public class Credential
{
public string Username { get; set; }
public string Password { get; set; }
}
The baseUrl is always set but the credentials variable is always NULL and I don't know why...
In the latest v4.0.31 of ServiceStack there's First Class support for AppSettings so you don't have to register it yourself as it's already registered for you:
container.Register<IAppSettings>(new AppSettings());
But I've tested this and it works as expected where it deserializes into a populated Credential instance with:
var credential = AppSettings.Get<Credential>("credential", null);
Are you sure you're using the exact key names? as your last sentence uses baseUrl and credentials but your appSettings says baseaddress and credential.
You would need something like this in your config <security mode="TransportWithMessageCredential"> to automatically add a security header to your post. Or you need to add and parse your own headers. You don't show your full web config or a sample call to your "Post" so I am running on some assumptions here.

'Confirm password' and 'Password' do not match. MVC5

I can't localize validate: 'Confirm password' and 'Password' do not match. in MVC5
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] //Why not display this message???????
public string ConfirmPassword { get; set; }
Please help me localize it.
You have 2 options to solve this bug:
--Option 1
Change:
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
to
[System.Web.Mvc.Compare("Password", ErrorMessage = "Your custom error message")]
--Option 2 (I recommend this one)
We need to update our ASP.NET MVC 5. In your Visual Studio go to the Package Manager Console and type:
PM> update-package
You migh get an error in the:
public ApplicationDbContext()
: base("DefaultConnection")
{
}
That error is caused by the update in the internal structure of MVC 5. To solve that error do this: https://stackoverflow.com/a/23090099/2958543
It appears that it is a known issue and is not working correctly at the moment - http://aspnetwebstack.codeplex.com/workitem/1401.
However a temporary workaround would be using the Compare attribute from System.Web.Mvc, which is marked obsolete. Here is an example:
using CompareObsolete = System.Web.Mvc.CompareAttribute;
...
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[CompareObsolete("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
I am currently using this workaround until the official fix is available. Everything is working perfectly fine - I am using this attribute to localize error messages using Resources.
Just don't forget to update it once the official fix comes out.
EDIT: The issue has been fixed in the latest release.
There seems to be two types of CompareAttribute. Looking at MSDN, the one with namespace System.Web.Mvc seems to be obsolete and they suggest using the one with namespace System.ComponentModel.DataAnnotations.
Link: https://msdn.microsoft.com/en-us/library/system.web.mvc.compareattribute(v=vs.118).aspx
With Visual Studios, you'll have to be explicit with the annotation and add the namespace to attribute in the annotation like the following:
[System.ComponentModel.DataAnnotations.CompareAttribute("Password", ErrorMessage = "The password and confirmation password do not match.")]
For more information, see also: System.ComponentModel.DataAnnotations.compare vs System.Web.Mvc.Compare

Resources