DynamoDB Session State in ASP.NET MVC - c#

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.

Related

ASP.NET Identity + Windows Authentication for Intranet Site

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>

Alternative to appsettings in web.config (persistance needed)

I'm currently having some configuration variables in my Web.config, eg:
<appSettings>
<add key="RecipientEmailForNotifications" value="asdf#sdf.com" />
<add key="NotifyNewEntries" value="true" />
<!-- etc... -->
</appSettings>
I have a view where admin users can change this values online, eg.
/Admin/Configuration/
Recipient email for notifications:
[___________]
Notify new entries:
[x] Yes
[SAVE]
But there are two problems with this approach:
Each time I deploy the web.config, I'm overriding those values that were saved online
Each time the web application restarts (because web applications are naturally stopped when there is no activity), these values that were saved online are reset to the originals of the last deployment
So the question is:
What is the best way of achieving this goal of having configuration variables that have to be persisted?
I think that using a table isn't very natural, but I might be wrong (please explain why).
Also, using app settings is very convenient when reading the values:
ConfigurationManager.AppSettings["RecipientEmailForNotifications"]
As opposed of using the database,
db.SomeConfigurationTable.SingleOrDefault(.....)
I'd use a combination of database store and caching.
If you are on a single web server you could store the settings in proc cache. If you are in a web farm you could look at something like couchbase (free memcached) or azure.
It might make sense to warm your cache on applicaiton start. That is read the settings from your database and populate your cache.
Another popular approach is to have a Get call that check the cache first and populate cache if cache is empty, e.g.
public string Get(string key, Func<string> getItemCallback)
{
var item = Cache.Get(key) as string;
if (item == null)
{
item = db.SomeConfigurationTable.SingleOrDefault(key);
Cache.Store(key, item);
}
return item;
}
Not forgetting you will need to burst your cache when updating settings.

ASP.NET Identity check user roles is not working

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.

Can you change the ConnectionString configuration value at runtime? Or... do I even need to?

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.

Using Customized Membership in Asp.Net

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

Categories

Resources