Lets say that you have websites www.xyz.com and www.abc.com.
Lets say that a user goes to www.abc.com and they get authenticated through the normal ASP .NET membership provider.
Then, from that site, they get sent to (redirection, linked, whatever works) site www.xyz.com, and the intent of site www.abc.com was to pass that user to the other site as the status of isAuthenticated, so that the site www.xyz.com does not ask for the credentials of said user again.
What would be needed for this to work? I have some constraints on this though, the user databases are completely separate, it is not internal to an organization, in all regards, it is like passing from stackoverflow.com to google as authenticated, it is that separate in nature. A link to a relevant article will suffice.
Try using FormAuthentication by setting the web.config authentication section like so:
<authentication mode="Forms">
<forms name=".ASPXAUTH" requireSSL="true"
protection="All"
enableCrossAppRedirects="true" />
</authentication>
Generate a machine key. Example: Easiest way to generate MachineKey – Tips and tricks: ASP.NET, IIS ...
When posting to the other application the authentication ticket is passed as a hidden field. While reading the post from the first app, the second app will read the encrypted ticket and authenticate the user. Here's an example of the page that passes that posts the field:
.aspx:
<form id="form1" runat="server">
<div>
<p><asp:Button ID="btnTransfer" runat="server" Text="Go" PostBackUrl="http://otherapp/" /></p>
<input id="hdnStreetCred" runat="server" type="hidden" />
</div>
</form>
code-behind:
protected void Page_Load(object sender, EventArgs e)
{
FormsIdentity cIdentity = Page.User.Identity as FormsIdentity;
if (cIdentity != null)
{
this.hdnStreetCred.ID = FormsAuthentication.FormsCookieName;
this.hdnStreetCred.Value = FormsAuthentication.Encrypt(((FormsIdentity)User.Identity).Ticket);
}
}
Also see the cross app form authentication section in Chapter 5 of this book from Wrox. It recommends answers like the ones above in addition to providing a homebrew SSO solution.
If you are using the built in membership system you can do cross sub-domain authentication with forms auth by using some like this in each web.config.
<authentication mode="Forms">
<forms name=".ASPXAUTH" loginUrl="~/Login.aspx" path="/"
protection="All"
domain="datasharp.co.uk"
enableCrossAppRedirects="true" />
</authentication>
Make sure that name, path, protection and domain are the same in all web.configs. If the sites are on different machines you will also need to ensure that the machineKey and validation and encryption keys are the same.
If you store user sessions in the database, you could simply check the existance of the Guid in the session table, if it exists, then the user already authenticated on the other domain. For this to work, you would have to included the session guid in the URL when you redirect the user over to the other website.
Not sure what you'd use for .NET but ordinarily I'd use memcached in a LAMP stack.
The resolution depends on the type of application and environment in which it is running. E.g. on intranet with NT Domain you can use NTLM to pass windows credentials directly to servers in intranet perimeter without any need to duplicate sessions.
The approach how to do this is generally named single sign-on (see Wikipedia).
There are multiple approaches to this problem, which is described as "Cross-domain Single Sign On". The wikipedia article pointed to by Matej is particularly helpful if you're looking for an open source solution - however - in a windows environment I belive you're best off with one of 2 approaches:
Buy a commercial SSO product (like SiteMinder or PingIdentity)
Use MicroSoft's cross-domain SSO solution, called ADFS - Active Direcctory Federation Services. (federation is the term for coordinating the behavior of multiple domains)
I have used SiteMinder and it works well, but it's expensive. If you're in an all MicroSoft environment I think ADFS is your best bet. Start with this ADFS whitepaper.
I would user something like CAS:
[1]: http://www.ja-sig.org/products/cas/ CAS
This is a solved problem and wouldn't recommend rolling your own.
Alternatively if you want to roll your own and the sites in question are not on the same servers or don't have access to a shared database (in which case see the above responses) then you could place a web beacon on each of the sites which would refer back to the other site.
Place a single pixel image (web beacon) on site A which would call site B passing through the users ID (encrypted & time stamped). This would then create a new user session on site B for the user which would be set as logged in. Then when the user visited site B they would already be logged in.
To minimise calls you could only place the web beacon on the home page and or log in confirmation pages. I've used this successfully in the past to pass information between partner sites.
Related
I have been working on a project where I have a simple web page integrated with AD FS. The authentication and website are working as expected. I am using VS 2015. My goal is to limit what users can access at the site, "roles" from what I have read and researched. If the logged on user is an admin, grant full access, but if logged on as a regular user limit what pages are available.
Here is the scenario, go to my project URL which is redirected to AD FS sign on, after successful sign on you are at my website. Not much to it.
I have read so much online about different ways to achieve my goal that I am unsure which course is best or simplest to configure. What are my best options here? Keep in mind I have never developed in asp or any other code for that matter. Any help would be appreciated.
There is policy based authorization that is probably the current best practice, however it sounds like role based authorization may be sufficient for you.
To perform role based authorization you'll first need to setup a claim rule in your ADFS for the Relying Party Trust of your application that sends the Role claim type "http://schemas.microsoft.com/ws/2008/06/identity/claims/role". The claim rule would look like this,
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> add(store = "Active Directory", types = ("http://schemas.microsoft.com/ws/2008/06/identity/claims/role"), query = ";tokenGroups;{0}", param = c.Value);
Then when your roles arrive at your application in these claims, you'll process them with Windows Identity Foundation (WIF), which is integrated into .NET Framework 4.5+. I believe referencing System.Security.Claims is sufficient to get WIF in your project for processing roles. This "processing" however is done for you by WIF.
At this point you should be able to simply decorate controllers and methods like the following to perform role based authorization, with these Roles equating to the names of groups you are a member of in Active Directory.
[Authorize(Roles = "Administrators")]
public class AdminController : Controller
{
}
Just for interest, there are other ways to do this.
Once you have the roles, you can use IsInRole(role).
You can also use the web.config e.g.
<location path="Page.aspx">
<system.web>
<authorization>
<allow roles="Admin, OtherAdmin" />
<deny users="*" />
</authorization>
</system.web>
ASP.NET Web Forms applications.
I checked our company's legacy code, the way they do login is like this:
when user is validated against database with (username, password), they set a session:
Session["authenticated"] = "true";
Every page other than login.aspx is inherited from a class named SecurePage. In SecurePage's OnInit() method, it checks
if (Session["authenticated"] != null)
if true, means authenticated, otherwise means not. So basically the way to do authentication is to see if there is a session named authenticated.
This seems the most crude and intuitive way of doing authentication... I want to ask: is this safe?
Another thing I feel strange is that in the web.config, they have this:
<authentication mode="Windows" />
Shouldn't it be
<authentication mode="Forms" />
since these are web applications? Users credentials are stored in database and these users are outside clients (not internal users).
A slight different version also does this after user is validated against database:
FormsAuthentication.SetAuthCookie( username, true );
what does this do? Besides this statement in login.aspx, I don't see any other pages have any code related to auth cookie. Do we need to set auth cookie by ourselves in code or does .NET framework handle this for us already?
Still another version have the following:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(login, false, 60);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
Response.Cookies.Add(cookie);
what does this do? Do we need to set this cookie by ourselves in code? or does .NET framework handle this for us already?
These web appliations were developed a long time ago, though I am not sure when. I suspect it is .NET 1.0 era? From my understanding since .NET 2.0,
it has this ASP.NET membership thing, and we can just use <authentication> and <authorization> tags in web.config (and subfolder web.config) to achieve the goal of authentication and authorization. Isn't it? Can anyone give me a history of ASP.NET framework authentiation mechanism? (membership -> simple memebership -> Identity?)
<authentication mode="Windows" />
Above should be used mostly in intranet website, because it's like saying use the computer(windows pc) authentication to access the resource. However, this will never work, since inherited class has a method to validate session key value for a login.
You should make sure that the code redirects user to login page in case the session key is not found. That means, in the else section of below code, you should take users to login page to try again. Which I am sure is happening.
if (Session["authenticated"] != null)
{ /*user is authenticated*/ }else{ /*redirect to login*/ }
Its is recommended to use <authentication mode="Forms" /> if the website is accessible over the internet. Other benefit of using this setting is that you can set default and login page.
Finally, FormsAuthenticationTicket is a class with property and values that are used when working with Forms authentication to identify authenticated users.
Read through msdn article to know more about asp.net membership.
https://msdn.microsoft.com/en-us/library/yh26yfzy%28v=vs.140%29.aspx
I've got 2 MVC3 Internet websites. One (Site1) uses Windows authentication and is in the Local Intranet Zone. The second (Site2) is publicly available and uses Forms Authentication. Both sites are in the same Domain, but have a different sub-domain. I want to share authentication cookies between the two. In order to do this, they need identical settings in the web config. Sometimes this works, most of the time it doesn't. If anyone hits Site1 from outside our network, they get a 403 error, which is good. If a network user hits Site1, they're allowed in based on their network credentials. I then check their user's roles with the code below.
var userName = string.Empty;
var winId = (WindowsIdentity)HttpContext.User.Identity;
var winPrincipal = new WindowsPrincipal(winId);
if(winPrincipal.IsInRole("SiteAdmin")) {
FormsAuthentication.SetAuthCookie("siteadmin", false);
userName = "siteadmin"; //This is a Forms Auth user
}
else if(///I check for other roles here and assign like above)
Once I've checked the roles, I forward them onto Site2, creating a cookie for them if the user is in one of the roles determined in the if...statement above.
if(!string.IsNullOrEmpty(userName)) {
//Add a cookie that Site2 will use for Authentication
var cookie = FormsAuthentication.GetAuthCookie(userName, false);
cookie.Domain = FormsAuthentication.CookieDomain; //This may need to be changed to actually set the Domain to the Domain of the TVAP site.
HttpContext.Response.Cookies.Add(cookie);
}
//Network users not found in roles will simply be forwarded without a cookie and have to login
HttpContext.Response.RedirectPermanent(tvapUrl);
I've set up in the web.config a matching MachineKey (validationkey, decryptionkey and validation) for each site.
They also both have the same authentiation settings, with the exception of the mode. So my config for this looks like this.
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" name=".ASPXFORMSAUTH" protection="All" path="/" domain="mydomain.com" enableCrossAppRedirects="true" timeout="2880" />
</authentication>
I think my problem is that the 'authentication' mode is different for each one, so Site2 won't use the authentication cookie from site1. This is just a guess though. Is there anyway I can figure out the issue?
According to this article, what I have going here should work. And there have been times where I think it's worked, but it's hard to tell, as I may have cookies cached and their getting reused. I'm hoping someone can see something I'm missing here, or has an alternative solution.
UPDATE
I checked my authentication cookie on Site2 after logging in normally and found the Domain wasn't set, so I've removed that line of code.
Also, I read about cookies expiring when the date isn't set, so I set an Expire Date on my cookie before sending with the request.
So, with those two changes, here's where I'm at.
It works on Chrome and Firefox, but not with IE. Not sure. I'm going to do some additional testing from another machine and another user so I know I haven't got any residual cookies sitting around.
I determined my problem was not setting the Expires property of my cookie. According this Microsoft article, cookies won't be written to the client unless the Expires property is set.
"If you do not set the cookie's expiration, the cookie is created but it is not stored on the user's hard disk. Instead, the cookie is maintained as part of the user's session information. When the user closes the browser, the cookie is discarded. A non-persistent cookie like this is useful for information that needs to be stored for only a short time or that for security reasons should not be written to disk on the client computer. For example, non-persistent cookies are useful if the user is working on a public computer, where you do not want to write the cookie to disk."
In this case, I needed the cookie to be written to disk since I was doing a server transfer to another site, thereby ending the session for that user. I'm not 100% sure that this was the fix, but it is working now, so I'm assuming that.
I am using Windows Identity Foundation with Azure's AppFabric Access Control Service in a MVC3 site. What I am trying to figure out is how to control where WIF redirects the user if I have an AuthorizeAttribute on a controller or action. (This is my first time working with WIF and there doesn't seem to be a lot of good information available.)
I have disabled auto-forwarding because it kept sending me to the default ACS authentication page. I want to keep users on my site using my custom login page, but I cannot seem to figure out what settings need to be tickled to do this.
Is there a way, natively with WIF, to tell it to redirect to my login page or am I going to have to write my own AuthorizeAttribute to do this for me?
Thanks!
Edit:
Since there has been some activity on this lately, I figured I would write out some of my findings. Unfortunately, I am not 100% what caused everything to work properly (so many moving parts) but I did finally get WIF to redirect to my login page.
I did this without adding any code to the program and, instead, deviated a little from the examples I found. I found that keeping the forms authentication portion of web.config allowed everything to work. In my web.config I have the normal forms auth entry:
<system.web>
<httpRuntime requestValidationMode="2.0" />
<authentication mode="Forms" >
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
...
</system.web>
Disclaimer: I do not know if this is the right way to do things with WIF--it just happens to solve my problem. I can use the regular [Authorize] attribute on controllers or actions and I get proper redirects to the login page as if I was using forms authentication.
I've played a little bit more with a sample and depending on what you need to do before redirecting, it might or ight not help.
In the global.asax, I've added a handler to the "RedirectingToIdentityProvider" event and I customized it to add say, the whr parameter. To do this, you need to first add a handler to the ConfigurationCreated event:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
FederatedAuthentication.ServiceConfigurationCreated += new EventHandler<Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs>(FederatedAuthentication_ServiceConfigurationCreated);
}
void FederatedAuthentication_ServiceConfigurationCreated(object sender, Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs e)
{
var m = FederatedAuthentication.WSFederationAuthenticationModule;
m.RedirectingToIdentityProvider += new EventHandler<RedirectingToIdentityProviderEventArgs>(m_RedirectingToIdentityProvider);
}
void m_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)
{
var sim = e.SignInRequestMessage;
sim.HomeRealm = "Google";
}
This works with the standard Authorize attribute.
If this extensibility point is not enough, then you can write our own attribute to have full control of the process.
Look at sample #3 or #7. Not MVC3, but on MVC2 and very close to what you are doing. http://claimsid.codeplex.com
The process is described here:
http://msdn.microsoft.com/en-us/library/ff966481.aspx#sec14
I believe what you want to do can be found in the following sample: http://acs.codeplex.com/wikipage?title=MVC3%20Custom%20Login&referringTitle=Samples
Also check the Configuration of Federated Authentication section on this page about the passiveRedirectEnabled property:
http://msdn.microsoft.com/en-us/library/ee517293.aspx
passiveRedirectEnabled - Boolean - default false
Controls whether the module is enabled to automatically redirect
unauthorized requests to an STS.
I have created a site in ASP.NET 3.5 & I have only 2 or 3 user login IDs who can login to the website.
What would be the best way to save these login details? Which of these approaches, or others, would be most suitable?
Using Forms Authentication, and saving credentials (username and password) in web.config
to create a text file in directory and modify it
Which approach is best from a security and maintenance perspective? What other approaches are suitable for a login system for ASP.NET?
Use the default ASP.NET Sql Membership Provider. The link will show you how to used it and get it configured.
Do you already have a database? If so, use forms authentication and ASP.NET membership like everyone says. It is real simple to integrate into your current database (assuming it's sql server - i don't know about others). I realize adding a DB for 2 or 3 users isn't always an option due to budget or whatever so you can use forms authentication and store the user in the web.config. I've done this in the past and it is very simple.
Your web.config will look like:
<authentication mode="Forms">
<forms loginUrl="Login.aspx">
<credentials passwordFormat="Clear">
<user name="myUser" password="password" />
</credentials>
</forms>
</authentication>
Then you can use the built in login controls. If you do it this way you need to implement the Autenticate event.
protected void Login1_Authenticate(object sender, System.Web.UI.WebControls.AuthenticateEventArgs e)
{
string UserName = Login1.UserName;
string Password = Login1.Password;
if (FormsAuthentication.Authenticate(UserName, Password))
{
e.Authenticated = true;
}
else
{
e.Authenticated = false;
}
}
Of course this isn't the most secure way to go about this, and you'll probably want to at least look at encrypting the credentials in the web.config, but it is simple and works when a database isn't an option.
With ASP.NET you can use some of the built-in/provided authentication providers that let you manage the users in a database and it uses proper guidelines like hashing passwords, etc. by default.
You could use ASP.NET membership. Even though you won't have many users, it handles all of the authentication details for you.