I have an ASP.NET MVC 5 application. I'm using the standard ASP.NET Identity provider for user and role management. It is important that I'm using the IdentityUser from an own repository project, but this seems ok. I can register, login, edit users, and manage their roles.
I add user to Role with these lines:
UserManager.AddToRole(userdetail.Id, r);
db.Entry(userdetail).State = EntityState.Modified;
db.SaveChanges();
This seems working in DB level.
But, I can't use Role based authentications, actually the simples
HttpContext.User.IsInRole("Administrator")
doesn't working too.
[Authorize(Roles="Administrator")]
doesn't working too.
I can check only with this method, whether user is an administrator:
UserManager.IsInRole(userID, "Administrator").
Why?
In every tutorial what I found, everything works fine. The different project repository could be the reason? Or ASP.NET Identity is broken so much?
Please advice,
There seems to be an issue. [The issue by design]
The role names are case sensitive in AuthorizeAttribute and User.IsInRole
The role names are case insensitive in UserManager.IsInRole
Moreover, check for the correct role name is used for the verification.
[The above is based on the test performed with below code. Role Name="Admin", User is added to Role "Admin".]
[Authorize(Roles="Admin")] /*True as "Admin" has A capital as entered in Role name*/
public ActionResult Secured()
{
if (User.IsInRole("admin")) /*This is False*/
{
Console.WriteLine("In");
}
if(UserManager.IsInRole(User.Identity.GetUserId(), "admin")) /*This is True!!*/
{
Console.WriteLine("In");
}
return View();
}
If we change the attribute to [Authorize(Roles="admin")], it redirects to Login page.
In that case you need to logout and login the user again.
Because the roles data is also stored in cookies,
So you must issue the cookie again to work it.
Do you have this entry in your web.config?
<roleManager enabled="true">
<providers>
<clear />
<add connectionStringName="ApplicationServices" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" applicationName="/" />
</providers>
</roleManager>
Also, if I remember correctly, there is a different namespace for the role provider assembly in different versions of .NET.
I was using IsInRoleAsync in Asp.Net core and in my case the problem was that I had ignored the role's normalized name when I created it. Therefore, after updating the normalized name for the role everything worked properly.
Related
I have create a new ASP.NET MVC 5 Project. I have installed through Nuget the AWS SDK for .NET and Session Provider and I have read this article in Amazon: Article
I have this configuration in the Web.Config
<sessionState
mode="Custom"
customProvider="DynamoDBSessionStoreProvider">
<providers>
<add name="DynamoDBSessionStoreProvider"
type="Amazon.SessionProvider.DynamoDBSessionStateStore, AWS.SessionProvider"
AWSProfileName="default"
Table="ASP.NET_SessionState"
Region="eu-west-1"
/>
</providers>
</sessionState>
I run the web app using the IIS Express and all works fine (I can login and logoff), but if I access to my DynamoDB I don't have any item in the table ASP.NET_SessionState.
It's working like the custom state provider is ignored...
What am I doing wrong?
Thanks!!
Are you storing anything in the session? If you are not you there is nothing to store and there will be no records in DynamoDB.
If you want to check that you have it setup correctly, run a test that adds some data into the session and then check DynamoDB. You should then see records there.
Using this in EC2 instance you should set up an IAM role for DynamoDB access. At the bottom of the article there is information on the role. http://aws.amazon.com/iam/ Then there should be no need for credentialing as it is handled in the VPC of your EC2 instance. Also make sure the sessionState tag is inside of the tag in your web.config.
This is what i have done
First need to login to amazon console and search for DynamoDB.
Then create a table with name ASP.NET_SessionState with key as SessionId (string), you need to set ReadCapacity to 3 and WriteCapacity to 1.
In Project Install packages AmazonSDK.Core and AmazonSDK.DynamoDBV2
In the web config in the system.web section
<sessionState timeout="20"
mode="Custom"
customProvider="DynamoDBSessionStoreProvider">
<providers>
<add name="DynamoDBSessionStoreProvider"
type="Amazon.SessionProvider.DynamoDBSessionStateStore, AWS.SessionProvider"
AWSAccessKey="{Access key}"
AWSSecretKey="{Sectret key}"
Table="ASP.NET_SessionState"
Region="us-east-1"
ReadCapacityUnits="3"
WriteCapacityUnits="1"/>
</providers>
</sessionState>
Then in the model you have give serializable Attribute. Some thing like below
[Serializable]
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Then in the code you need to set session, something like this
TestModel testModel = new TestModel();
testModel.Id = 1;
testModel.Name = "ItemName";
// When we add this to session an entry will be written to DynamoDB Asp.NetSessionTable
Session["Checkout"] = testModel;
No need to worry about connection amazon sdk will take care of it. You need to mention the correct Access key and Secret Key.
I am building an intranet site where users will be on the corporate domain and have different permission levels. I'm currently using <authentication mode="Windows"/> to control site access, but it seems like I should be using ASP.NET Identity.
For example, say my application is a dashboard for each department in the organization. I want to create a single AD group called DashboardUsers and put everyone that can touch the site in this group.
I also want to restrict the views in the dashboard. For example, I only want the IT group to see their view, and the Finance folks see theirs, etc.
Question -- should I be using Windows Authentication to control access to the site, and then use ASP.NET Identity for user level permissions?
I have done something similar to this using only WindowsAuthentication. You can tag your actions with the Authorize Attribute:
[Authorize(Roles = #"DashboardUsers")]
As long is this user is a member of the DashboardUsers AD group they will get access to this action. It seems like MVC magic, but it really is that simple.
Unfortunately this approach will not allow you to overload an action for different Roles as the Authorize Attribute is not part of the method's signature. In your views, you would have to show different anchor tags based on the current users role.
ie:
[Authorize(Roles = #"DashboardUsers\Manager")]
public ActionResult IndexManagers()
{
..
}
or
[Authorize(Roles = #"DashboardUsers\Finance")]
public ActionResult IndexFinance()
{
..
}
EDIT AFTER COMMENT:
Since your Identity is coming from AD, you could use logic in your controller like:
if(User.IsInRole("Finance"))
{
..
}
else if(User.IsInRole("IT"))
{
..
}
And this will check which AD Group they belong too. I know it's not very elegant, but I can't imagine mixing Windows Auth with a custom identity and managing permissions in your own db would be elegant either.
I have run into this dilemma before and wound up creating a custom role provider that i used in conjunction with windows authentication. I'm not sure you need the OWIN middleware when authenticating against AD.
public class MyAwesomeRoleProvider : RoleProvider
{
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
// i talk to my database via entityframework in here to add a user to a role.
}
// override all the methods for your own role provider
}
config file
<system.web>
<authentication mode="Windows" />
<roleManager enabled="true" defaultProvider="MyAwesomeRoleManager">
<providers>
<clear />
<add name="MyAwesomeRoleManager" type="MyAwesomeNamespace.MyAwesomeRoleProvider" connectionStringName="MyAwesomeContext" applicationName="MyAwesomeApplication" />
</providers>
</roleManager>
</system.web>
First post, I'm a complete .Net/C# novice thrown in at the deep end!
I've inherited a C# wed application due to someone leaving at work and me being the only one with bandwidth! But not the .Net, C# knowledge!
The app is used by people on different sites all over the world. They log in using the corporate login details and as such they log into different servers depending on where they are located, (Europe, America or India).
The guy who wrote the app couldn't work out how to switch the ConnectionString in web.config depending on location, so duplicated the whole app for each domain! With the only variation being a single IP address in web.config for each duplicated version of the app! Then did a simple web front page which took the user to "their" version of the app depending on where they said they were in the world!
The first thing I want to do is to move to a single version to maintain, so I need to be able to switch the connection string or how to login?
I've spent several days trying to work out how I get to ConnectionString (defined in web.config) from my Login class, only to discover the values set in web.config seem to be read only, so I can't alter them.
So I guess the first question is, am I barking up the wrong tree? Can I just set all the information that AspNetActiveDirectoryMembershipProvider (see code later) requires and call it from my login class? Or is the ConnectionString route the Ipso facto way to set up connections in .Net/C#? So therefor I do need to find out how to change/specify/add the value at runtime.
Three possibilities I can think of:- (The first is the one I've ground to a hult with)
Change the ConnectionString for ADService in my web.config from my Login class?
Change what AspNetActiveDirectoryMembershipProvider uses, so from my Login class magicly get it to use EMEA_ADService or PACIFIC_ADService as defined in web.config?
Is it possible to define a new connectionString and call AspNetActiveDirectoryMembershipProvider all from my Login class, not using web.config for this connection at all?
Here's a bit of my/his web.config file and my Login class
Cuttings from Web.config
<connectionStrings>
<add name="ADService" connectionString="LDAP://12.345.67.8" /> *---- Original ConnectionString (IP address changed)----*
<add name="EMEA_ADService" connectionString="LDAP://12.345.67.8" /> *---- Added by me playing around unsuccessfully! ----*
<add name="PACIFIC_ADService" connectionString="LDAP://12.345.67.9" /> *---- Added by me playing around unsuccessfully! ----*
~
</connectionStrings>
<authentication mode="Forms">
<forms loginUrl="~/Login.aspx" timeout="2880" /> *---- The background class for this popup (Login.aspx.cs) is where I'm currently trying to affect ConnectionString----*
</authentication>
*---- Pretty sure this is the bit that actually does the login verification----*
<membership defaultProvider="AspNetActiveDirectoryMembershipProvider">
<providers>
<clear />
<add name="AspNetActiveDirectoryMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=12345678" connectionStringName="ADService" applicationName="/." description="ADService" />
</providers>
</membership>
This is as far as I've got in my class before finding out that I don't appear to be able to alter ConnectionString!
Cuttings from Login.aspx.cs
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ConnectionStringSettingsCollection connections = ConfigurationManager.ConnectionStrings; //this is now working :)
string userDomain = Environment.UserDomainName; //Probably don't need this, it seems to give the login domain on the machine. Don't know yet if that will be the users machine or the server the app runs on?
if (connections.Count != 0)
{
foreach (ConnectionStringSettings connection in connections)
{
string testname = connections["ADService"].Name;
string testConnectionString = connections["ADService"].ConnectionString;
connections["ADService"].ConnectionString = "LDAP://12.345.67.9";
testConnectionString = connections["ADService"].ConnectionString;
Any hint would be very welcome!
P.S. I have requested a .Net/C# course at work! ;)
You wouldn't want to alter the existing connection string. Rather, you'd want to alter which connection string your Data Access Layer was using to call different service stacks. You could then choose a connection string at runtime based on whatever input parameters you wanted to use. which in your case might be an IP range.
asp.net mvc multiple connection strings
Handling multiple connection strings in ONE DataAccess Layer
http://msdn.microsoft.com/en-us/library/aa479086.aspx
The microsoft article is particularly interesting since it actually takes an architectural look at proper patterns for resolving dilemmas like yours. I think you got stuck with the short end of the stick! Best of luck!
The Web.config cannot be modified at Runtime. I would suggest setting some kind of flag via a login link or combobox on the website for people to use to choose where they want to login. It is not the job of the server to figure out what a user wants to do.
I am using Asp.Net/C# in my application , I am using Asp.Net built-in membership framework .The installation of aspnet_regsql services have been properly installed on my database.The aspnet_users table however contains basic information about the user , How do I add additional information about a user.Should I modify the table itself or should I use another table and link it with aspnet_users table.Also the Membership.ValidateUser(username,password) works well , but I have a requirement where the login is based on the user code.How can I achieve this , is it possible with built-in Membership.
Any suggestions are most welcome.
Thanks
Use an ASP.NET Profile-Provider instead.
https://web.archive.org/web/20211020111657/https://www.4guysfromrolla.com/articles/101106-1.aspx
You can store any kind of additional information even binary(images).
I've used The SqlProfileProvide myself in my current application to let the user himself select his startpage.
Therefor i just needed to add this to the web.config:
<profile defaultProvider="AspNetSqlProfileProvider">
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="RM2ConnectionString" applicationName="/ERP"/>
</providers>
<properties>
<add name="Startpage"/>
</properties>
</profile>
And i could write this property in codebehind:
if(User.Identity.IsAuthenticated)
{
HttpContext.Current.Profile.SetPropertyValue("Startpage", startPage); //startPage is a String
HttpContext.Current.Profile.Save();
}
and read it in the following way:
if(User.Identity.IsAuthenticated)
{
Dim user = Membership.GetUser();
Dim startPage = HttpContext.Current.Profile.GetPropertyValue("Startpage") as String;
}
You can store anything you want, see the link above for further informations.
You can use the ProfileProvider (ref).
More info here: http://msdn.microsoft.com/en-us/library/2y3fs9xs.aspx
And here: How to assign Profile values?
You could create a custom membership provider by inheriting from System.Web.Security.MembershipProvider - this way you can implement any additional functionality you need. You can then store the user details in your own table structure etc. You'd then point your web.config at your custom provider to use it.
Useful links:
http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx
http://www.asp.net/web-forms/videos/how-do-i/how-do-i-create-a-custom-membership-provider
http://www.devx.com/asp/Article/29256
I am using an email address as my "username" for Login. When a user logs in the User object that is created has the Email address as the name which is incorrect. The actual name is another field in the DB. How do I login and authenticate against the email address and then load the correct name in the User object?
I am using forms authentication with a custom MembershipProvider and RoleProvider.
Edits Below to Clarify
I have a custom MembershipProvider that validates users by email address and password. It is called by the basic Login Control and registered in web.config.
<asp:Login ID="AdminLogin" runat="server" MembershipProvider="AdminMembershipProvider">
</asp:Login>
Web.Config:
<authentication mode="Forms">
<forms loginUrl="Default.aspx" />
</authentication>
<membership defaultProvider="AdminMembershipProvider">
<providers>
<clear />
<add name="AdminMembershipProvider"
type="AdminMembershipProvider"
connectionStringName="EvalSysConnectionString"
/>
</providers>
</membership>
With just this my users are logged in correctly. However it returns a Context.User.Identity.Name of the email address. I have the first name and last name stored in the DB and want this to be the Name.
I read various posts that seem to indicate that I would have to create a Global.asax file and override the PostAutheticateRequest method to do this. However I have no idea how to proceed with this strategy.
<%# Application Language="C#" %>
<script runat="server">
protected void Application_PostAuthenticateRequest()
{
string test = HttpContext.Current.User.ToString();
}
</script>
I'm sorry my question was so vague. I'm so lost with this that I don't know how to write a good question.
I believe what you are asking is: Can I change the property Context.User.Identity.Name to display something other than the username?
EDIT
It is not possible using the implementation of the property Context.User.Identity.Name as it is read-only and is set to the username with no way to change it.
A quick and easy solution
You can write a method that calls a stored procedure (or query in your code) in your database to do a lookup based on the value in Context.User.Identity.Name and returns First and Last. You can store the result in a Session variable or use the Profile object (as noted below).
Alternate solution
You can write your own implementation of IIdentity. It's something I've never done, so I don't have any snippets to contribute. However this link should give you a place to start. I'd be careful with this solution since you lose your unique way of identifying a user unless you add an additional property to your implementation of IIdentity and make sure you cast Context.User.Identity, whenever referenced, to your own implementation.
Hope that helps.
I would do exactly what you have done so far and then store the users name, address and so on in the Profile object.
This is as easy as adding some configuration (web.config):
<profile>
<providers>
<clear />
<add name="SqlProvider"
type="System.Web.Profile.SqlProfileProvider"
connectionStringName="SqlServices"
applicationName="SampleApplication"
description="SqlProfileProvider for SampleApplication" />
</providers>
<properties>
<add name="Name" />
</properties>
</profile>
And then retrieve/set it like so:
txtName.Text = Profile.Name;
Profile.Name = txtName.Text;
You could definitely look into using a Profile provider like Jimmy suggested. Or, you could implement an IPrincipal and set the HttpContext.User property in your PostAuthenticateRequest event.
Basically, you just do something like
var userName = Database.GetUserName(httpContext);
httpContext.User = new GenericPrincipal(new GenericIdentity(userName, "FORMS"), new[] {"UserRole1"});
The first line is an example of a call to your db to get the username. The second line creates a principal and identity from this info then assigns it to the User property of the HttpContext
Dim username As String = Membership.GetUserNameByEmail(txtUsername.Text)
If (Membership.ValidateUser(username, txtPassword.Text)) Then
Here is some Vb code. that seems to retain the columns in the Membership Provider. Basically you allow a user to enter their email address which is unique and get their username using an email address. Then use the validation method to authenticate the user by their username and password.
What do you think guys.