Specifying password field to SimpleMembershipProvider - asp.net-mvc-4

I'm implementing SimpleMembershipProvider in a small MVC4 project, and I can already initialize the database connection using a customer-provided DB with the user and role tables already specified (those are called sp_person and sp_role).
The problem is, when I try to log in, the MVC app rejects my password with the typical "incorrect password" error message though I already know that it's the correct password. I suspect the problem is that SimpleMembershipProvider does not know where do I store the password (it's in the sp_person table, in the "ecampus_password" field) and that's why authentication fails.
How can I tell SimpleMembershipProvider where to look for the stored password?
Thanks in advance,
Léster

Nevermind, I found that SimpleMembershipProvider is not the solution. In this case, I'm supposed to implement a custom provider.
Steps as follows:
Add an Entity Data Model to the project that consumes only the tables related to the auth scheme (in my case, importing only sp_person and sp_role).
Add System.Web.ApplicationServices as a reference to the project.
Add a new class to the project, point to System.Web.Security in a using statement and make the class inherit from MembershipProvider. MembershipProvider is an abstract class, so implement it when asked.
Add an object to the class of the type Entity Framework created for you when you added the data model (it's usually called <CONNECTION_NAME>Entities, you can change that when creating the model). Something like this:
public class MyMembershipProvider : MembershipProvider
{
private MYCONNECTIONEntities db = new MYCONNECTIONEntities ();
}
Strictly, you might have to implement every property and method in the class, but for auth, you must implement ValidateUser(). Simply using a LINQ query to retrieve the user from your data model will do. Here's mine:
var list = from u in db.st_person
where u.ecampus_login == username
&& u.person_password == password
select u;
return list.Count() > 0;
In web.config, under the <authentication> element, add the new provider like this:
<membership defaultProvider="MyMembershipProvider">
<providers>
<clear />
<add name="MyMembershipProvider" type="PROJECT_NAME.MyMembershipProvider"/>
</providers>
</membership>
Compile and test.

Related

Using Local DB in MVC 4 application

I'm learning MVC. I just need to clear something. I'm following THIS tutorial. This guy uses LocalDB to store Movie object. He just adds a connection string and then after adding controller, as described in tutorial, CRUD action methods are automatically added. that guy used sentence something like, "that's all you have to do to store your movie object in your localdb". Database is automatically created (code first approach). (I know how to work with Entity Framework, where we have to create some model to map our database). But this tutorial is confusing me. There's nothing mentioned about creating database etc. while his connection string contains a word, "Movie.mdf" (under Data Source). Finally, following him, I'm getting server not found error (26). Am i missing something, as new to MVC?
Got the solution. The problem actually was that I was not calling the base constructor for dbContext class. Because I was assuming that keeping the name of the connection string and my class same will be enough. But it didn't work, and no db was created. I changed it as following piece of code, and it worked.
public class myDbClass : DbContext
{
public myDbClass()
: base("myConString")
{
//logic;
}
}
connection string is first placed with the SAME name in web.config, so that it can look up for.
<connectionStrings>
<add name="myConString" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
Is Local Db installed on your machine? It's installed when you install MS SQL server, but I think you have a checkmark, it's not installed by default.
When you install EntityFramework from NuGet, localdb is the default in your web.config, so it's true there is normally nothing else to do, even if it might not be the best way.

Adding List<T> property to ASP.net MembershipUser object MVC 4

I have created ASP.net MVC4 application with Internet application template,
and want to add List<T> property to MembershipUser object provided by ASP builtin Forms Authetication.
This List property will be a list of StockPermission object:
public class StockPermission
{
private Stock stock;
private byte afterSaveAction;
private bool allowEditingStockDocs;
private bool allowChangingUser;
}
Therefore my MembershipUser will contain StockPermission objects
which let MembershipUser to perform defined action with those Stocks in the List
Before you start trying to do something like this, it would be wise for you to read up on exactly what these systems are. It's clear from your comments that you don't really understand them because you're confusing multiple systems.
FormsAUthentication has nothing to do with MembershipUser. FormsAuthentication is only about providing a cookie for each web request to be shown as authenticated. FormsAuthentication can be used with any kind of credential system.
MembershipUser is part of the Membership subsystem. Membership has nothing to do with FormsAuthentication, other than your code will call into Membership to validate the users credentials, then your code will create a cookie using FormsAuthentication to log the user in.
The changes you want to make are related to permissions, and permissions are not part of the Membership system, they are part of the Role system. These systems are separate for a reason, because they can be replaced with custom implementations. and they have logically different functionality.
Finally, you can't change the MembershipUser, as it's part of the basic framework. You could extend it by deriving your own class from MembershipUser, but that's not the recommended way to do things. You should, instead, have your own User class which references the MembershipUser.ProviderUserId.
In short, you're about to dig into the internals of the framework. This is not something you should do without understanding more about what this is.
To add List property to our MembershipUser object or any other properties we can create custom MembershipProvider and custom MembershipUser classes describer in this article:
http://msdn.microsoft.com/en-us/library/ms366730(v=vs.100).aspx

I cannot figure out how to use the SimpleMembershipProvider.GetUserNameByEmail Method

This is a MVC 4 Internet application. I have set the Role Provider and Role Manager to SimpleRoleProvider and SimpleMembershipProvider in the Web.config file, but I continue to get the "You must call the "WebSecurity.InitializeDatabaseConnection" method before you call any other method of the "WebSecurity" class" exception despite initializing WebSecurity.InitializeDatabaseConnection in the Global,asax.cs file. I know this was initialized properly because the Roles property in the Authorize Attribute I have created and assign programmatically work perfect. All I want to do is retrieve a Users UserName and email it to them if they forget and cannot login. Advice appreciated.
[HttpPost]
[CaptchaVerify("Captcha is not valid")]
[AllowAnonymous]
public ActionResult ForgotUserNameOrPassword(UserProfile model, FormCollection collection)
{
if (!ModelState.IsValid)
{
ViewBag.Error = "The Captcha answer is incorrect";
return View();
}
else
{
SimpleMembershipProvider mySMP = new SimpleMembershipProvider();
int outRecs;
dynamic email = new Postal.Email("UserNameEmail");
MembershipUserCollection myUserCol =mySMP.FindUsersByEmail(model.UserEmail, 0, 0, out outRecs);
email.Username = myUserCol;
email.To = model.UserEmail;
email.From = model.UserEmail;
email.Send();
return View("../Account/Login");
}
}
Even if you did call InitializeDatabaseConnection properly it would not work for SimpleMembershipProvider.FindUsersByEmail. Here is a note in the documentation for this method.
If the SimpleMembershipProvider class has been initialized using a call to the WebSecurity.InitializeDatabaseConnection() method, this method is not supported and will throw a NotSupportedException exception. However, if the WebSecurity.InitializeDatabaseConnection() method has not been called, and if you have configured your site to use the standard ASP.NET membership provider, this method is passed through to the standard membership provider. For more information, see the SimpleMembershipProvider class overview.
What you are experiencing does not make any sense given the documentation. Where exactly is the exception being thrown? When you call FindUsersByEmail?
Updated 6/28/13
SimpleMembershipProvider does not implement all of the standard provider methods. If a method is missing you have a couple of options. First you can create your own custom SimpleMembershipProvider that is derived from the original that has the methods you need. Or you can extend the WebSecurity class to include the methods you need. Take a look at the SimpleSecurity open source project which decouples SimpleMembership from the ASP.NET MVC application. This article describes how to extend the WebSecurity class and queries the database directly. You can do something similar and query for a particular user by their email address.
But SimpleMembership does not support storing the users email address out-of-the-box. Take a look at this article on how to customize SimpleMembership to include the email address.
Also keep in mind that the reason that the base membership provider returns multiple users for an email address is that the schema does not restrict a user from opening multiple accounts with the same email address, unless the email address is used as the username.

Using MVC 4 SimpleMembership with an existing database-first EF model

I am trying to use SimpleMembership in my MVC 4 for the first time and I already have an existing database and EF5 model created based on it! I searched a lot but I cant find how I could use it in my case and also to have everything under my own model.
It would be great if somebody can give me an idea how to do this.
Thanks
Purely as a point of reference, it might be a good idea to create a new Internet Application template of an ASP.NET MVC 4 Web Application project (i.e. via File > New Project).
If you look at the AccountController, as #zms6445 says, it is decorated with an InitializeSimpleMembership attribute. You can find the implementation of this attribute in the InitializeSimpleMembershipAttribute.cs file in the Filters folder within the root directory.
In here, this is the missing part of the puzzle - you need to hook up your existing database so that it is used by the SimpleMembershipProvider. This is the code you need:
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
try
{
if (!WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection("CONNECTION_STRING_NAME", "USER_TABLE", "USER_ID_FIELD", "USER_NAME_FIELD", autoCreateTables: true);
}
}
catch (Exception ex)
{
throw new InvalidOperationException("Something is wrong", ex);
}
}
}
Some things to note:
CONNECTION_STRING_NAME is an entry in your web.config ConnectionStrings - you CANNOT use the model connection string here - the SimpleMembershipProvider does not recognise that format! You need to specify an System.Data.SqlClient connection string, e.g.
<add name="CONNECTION_STRING_NAME" connectionString="data source=SERVER;initial catalog=DATABASE;user id=USER;password=PASSWORD;" providerName="System.Data.SqlClient" />
USER_TABLE is the table in your database to hold extra user information, such as first name, surname etc. This is linked to the autogenerated tables via the USER_ID_FIELD.
USER_ID_FIELD is usually the primary key of your Users table. It must be of type int.
USER_ID_NAME is a unique name for the user, which could be an Email address.
autoCreateTables is set to true to ensure the tables required for the SimpleMembership to work are created if they don't already exist.
Of course, this code only gets fired if you hit a page via the AccountController, since this has been decorated by the attribute. You could put a breakpoint in there and see it in action.
This should get you started - the Internet Application template is a pretty good template to follow if you get stuck.
Hope this helps.
In your web.config in the appSettings tag, add the line
<add key="enableSimpleMembership" value="true"/>
SimpleMembership is built in so from here you simply need to write
[InitializeSimpleMembership]
above your public class AccountController: Controller
When you want to force a user to log in for a certain page you write in the pages controller
[Authorize]
That tables will be automatically generated in your database. If you want to add more fields to these tables you will need to simply google it.
Here's a link for more information http://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx

OData Authentication

I have been trying to implement an OData service based upon an entity framework model where the authentication is provided by Sql Azure. I provide row/column access within the database.
I want to be able to call this from LinqPad, Excel, etc. as a secure service.
I have tried the various schemes defined in the standard series but even though returning 401, neither Excel or LinqPad recall with the user name and password I've entered.
So, I thought I'd make the user name/password a query parameter (over SSL). But it turns out that's illegal as well (OData requires a well formed URL with no query parameters).
So then I thought, why not use WebGet to embed the user name and password in the URL but I can't get that to work with the OData source format in WCF:
<%# ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory, System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Service="WebApplication5.OData" %>
public class OData : DataService< MyEntities >
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
protected override MyEntities CreateDataSource()
{
// create the OData source with the user name and password here
}
}
Has anyone actually got OData to work where the user name and password are passed into the source?
I've not used a username and password per-say but I have authenticated by an API key which is technically the same. See my answer here: WPF and WCF Data Services Authenticate at Query level? - I use HTTP headers to authenticate: Args.OperationContext.RequestHeaders["APIKey"]) but you can change this to Args.OperationContext.QueryString["APIKey"]) (not sure if QueryString is a property of the top of my head) to allow passing in ?APIKey=blah in the URL.
I had a similar problem with OData for a Silverlight App with C# in that you had to create a new Uri (Url) and add in the credentials, either here or you can create a login screen to populate them:
ServiceReference1.NAV nav = new ServiceReference1.NAV(new
Uri("http:...../OData/Company('company_name')/"));
nav.Credentials = new System.Net.NetworkCredential("user", "password",
"domain");