We use Sharepoint 2007 as our internal portal. I'm currently developing a custom app (asp.net MVC2) and I've been asked to have the login process mimic Sharepoint, where a user is initially logged in using SSO but then can opt to logout and provide different credentials.
Any blogs/guides on how to do this?
UPDATE:
Thanks to reflector I was able to find a way to do this, but it doesn't totally work.
First off, I'm testing this on IIS running on my local Windows 7 machine.
I have setup the "LogOff" action to do the following:
var current = System.Web.HttpContext.Current;
var response = current.Response;
object obj2 = current.Items["ResponseEnded"];
if ((obj2 == null) || !((bool)obj2))
{
current.Items["ResponseEnded"] = true;
response.StatusCode = 401;
response.Clear();
response.Write("401 UNAUTHORIZED");
response.End();
}
This partially works. When I click "logOFf" I get prompted for credentials. Oddly enough, when debugging, I can see the method gets called twice (this is an MVC action).
But, even when providing valid credentials I still can't log back in. After the third try I get a 401 page.
My only thought here is somehow it's trying to use Kerberos to authenticate and since I don't have Kerberos setup on this machine it fails. But, when I first access the site from IE it just passes me IE credentials on (the SSO) and everything works fine, so I'm not sure why a second authentication fails.
asp.net membership provider is a great choice. There are a lot of options for authentication methods, based on your question though I think the .net membership provider would be your best bet. If you are using simply windows authentication, even sharepoint has its faults as IE will attempt to change the login back to the windows account user.
http://msdn.microsoft.com/en-us/library/yh26yfzy.aspx
Related
I'm building a simple CMS using ASP.NET MVC 5 and Entity Framework 6. I have 2 sites: Public and Admin. Public site to diplay all the content and Admin site to manage all the content.
I only need a single Admin account to handle all the content in the Admin site.
I'm thinking to use a session to keep the logged in user data and check for the session details when accessing an authorized page.
Keep the user data in a session.
var obj = db.UserProfiles.Where(a => a.UserName.Equals(objUser.UserName) && a.Password.Equals(objUser.Password)).FirstOrDefault();
if (obj != null)
{
Session["UserID"] = obj.UserId.ToString();
Session["UserName"] = obj.UserName.ToString();
return RedirectToAction("UserDashBoard");
}
Check before accessing an authorized page.
public ActionResult UserDashBoard()
{
if (Session["UserID"] != null)
{
return View();
} else
{
return RedirectToAction("Login");
}
}
So with this approach I wouldn't need to implement advance ASP Identity functions for the authorization.
Is this approach correct and would there be any downsides using this approach?
NEVER EVER EVER EVER EVER use session for authentication. It's insecure for starters, and it won't survive a loss of session (which IIS can kill at any time, for any reason). Session cookies are not encrypted, so they can be grabbed and used easily (assuming a non-encrypted link, even if you use HTTPS for authentication pages).
Another issue is that you are doing your authentication way too late in the pipeline. OnAuthenticate runs at the very beginning of the pipeline, while you action methods are towards the end. This means that the site is doing a lot of work it doesn't have to do if the user is not authorized.
I'm not sure why you are so against using Identity, the MVC basic templates already roll a full identity implementation for you. You don't have to do much.
The downside is that you have to write it all yourself anyway. You already need role-based authorisation and have to write cludges. Identity already have this implemented and tested for you. Also keeping information in session is not very secure.
And you don't need to implement much yourself anyway. Yes, there are lot of functionality that you'll probably won't need, but just don't use it.
Don't build your own authorisation system. Since you ask this question, you are probably not qualified enough to make it secure.
I have a problem in SignalR connection with Win Auth. When I enable anonymous in IIS Authorize settings, it works but sometimes it gives HTTP 403 Forbidden error. After I researched, I found that I need to disable Anonymous Connections. But when disable and enable the windowsAuth in IIS then there is always HTTP 401.2 UnAuthorized error. How I can connect with WinAuth? For my project I need to use WinAuth.
Not1 : I am using Silverlight 5.
Not2 : I have already tried possible solutions on StackOverflow but none of them worked.
So why cant I use WinAuth? It is enabled everywhere in config files, in IIS settings as well as in my web.config.
I spent 2 days but still I could not find a solution. If you need more information just write a comment. I am not sure what else information I can share. I dont want to put here lots of unnecessary texts.
EDIT:
When I use this code, i.e if I enter the username and password explicitly then it works. Internet Explorer first uses Anonymous Authentication and then it fails then it uses NetworkCredentials directly. This is the code
hubConnection = new HubConnection("URL");
hub = hubConnection.CreateHubProxy("HUBNAME");
hubConnection.Credentials = new System.Net.NetworkCredential("ID", "PASSWORD");
(The ones with capital letters are specific to my app.)
So how can I get Windows Credentials for my Silverlight App? DefaultCredentials does not work for silverlight.
Have you added authorization to your hub?
[Authorize(Roles = "Admin")]
public class AdminAuthHub : Hub
{
}
I have a WebApi using Basic Auth nicely. And I have an MVC site using Forms Auth nicely. But here's the catch:
Client X has a dedicated database with any number of Contacts and Products. The MVC site is a dedicated site for them (via {clientId} routing), which allows their Contacts to log in (via Forms Auth) and place orders for their products. The Contact must be Form-ly logged in to place an order.
The product orders (need to) hit the WebApi to be recorded in the Client's database.
But since the WebApi uses Basic Auth to validate the Client, not the Contacts who placed the orders, every request comes back is 401 - Unauthorized.
I've checked out ThinkTecture as suggested by a number of posts here on SO, however it doesn't get me what I need because I'm not looking to allow Forms Auth in the WebApi. I don't want to authenticate the Contact from the Client's database in the WebApi, I want to authenticate the Client in the WebApi.
Has anyone come across a similar scenario and am I missing something glaringly obvious? Perhaps I need to implement both Forms and Basic on the site?
The very standard Api call I'm making from the site (where the UserName and Password are the Client's, not the Contact's):
var clientId = new Guid(RouteData.Values["clientId"].ToString());
var baseUrl = ConfigurationManager.AppSettings["ApiBaseAddress"];
var authHeader = Convert.ToBase64String(Encoding.ASCII.GetBytes(String.Format("{0}:{1}", _shoppingCartSettings.UserName, _shoppingCartSettings.Password)));
var requestUrl = String.Format("api/{0}/inventory", clientId.ToString());
var httpWebRequest = WebRequest.Create(baseUrl + requestUrl);
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "Basic " + authHeader);
httpWebRequest.Method = "GET";
httpWebRequest.Accept = "application/json";
httpWebRequest.ContentType = "application/json";
try
{
using (var httpWebResponse = httpWebRequest.GetResponse())
{
// we never get here because of a 401
}
}
catch (WebException ex)
{
using (var httpWebResponse = ex.Response)
{
// we always get here
}
}
If I set up a separate test client and make the same call, it works great :/
Is your Web API under the same virtual directory and configuration as the MVC site? It looks like the Forms Auth HTTP module kicks in for your API, which you don't want. As long as you don't plan to call the API directly from the browser, move it to a separate virtual directory that is set up exclusively for basic auth, no forms auth module in the web.config for the API.
Why not have one login for your MVC site that has the ability to submit orders for every Client? It makes sense for your WebAPI to only allow Clients to submit orders for themselves. But I don't think it makes sense to have your MVC site authenticate as different Clients based on the Contact. Your MVC site would have to store the passwords for each Client.
Instead, create one login for the MVC site and give it the ability to submit an order for any Client.
After much banging of head against the not-so-proverbial wall, and a much needed shove by #0leg, I've discovered the cause.
In the Properties of my WebApi project file under Web > Servers, the Visual Studio Development Server was being used with a Virtual Path of "/", whereas my MVC project file was set up to use the Local IIS Web Server. The MVC project also had the Apply server settings to all users (store in project file) option checked.
Setting both to use the local IIS server resolved it.
Upon further contemplation, this now seems logical since they were essentially running on different servers.
Posting this for posterity's sake.
We have a lot of domains running on one IIS WebSite/AppPool.
Right now we are in the process of implementing SSO with Windows Identity Foundation.
in web.config the realm has to be set with
<wsFederation passiveRedirectEnabled="true" issuer="http://issuer.com" realm="http://realm.com" requireHttps="false" />
My problem is that the realm is dependent on which domain the user accessed the website on
so what I did is that I set it in an global action filter like this
var module = context.HttpContext.ApplicationInstance.Modules["WSFederationAuthenticationModule"] as WSFederationAuthenticationModule;
module.Realm = "http://" + siteInfo.DomainName;
My question is. When I set the realm like this, is it set per user instance
or application instance.
Scenario.
User A loads the page and the realm get set to domain.a.com.
User B is already logged in on domain.b.com and presses login.
Since user A loaded the page before User B pressed login, user A will hit the STS
with the wrong realm set.
What will happen here?
If this is not the way to set the realm per user instance, is there another way to do it?
I have already solved the problem.
I set PassiveRedirectEnabled to false in web.config
I set up the mvc project to use forms authentication, eventhough I dont.
I do that so that I will get redirected to my login controller with a return url everytime a controller with [Authorize] is run.
In my login controller I do
var module = HttpContext.ApplicationInstance.Modules["WSFederationAuthenticationModule"] as WSFederationAuthenticationModule;
module.PassiveRedirectEnabled = true;
SignInRequestMessage mess = module.CreateSignInRequest("passive", returnUrl, false);
mess.Realm = "http://" + Request.Url.Host.ToLower();
HttpContext.Response.Redirect(mess.WriteQueryString());
This is definitely not really how it should be, for me it feels like Windows Identity Foundation is lagging behind, both in documentation and microsoft technology wise, no examples for MVC.
For other MVC people i recommend them to not use the fedutil wizard, and instead write the code and configuration themself
We have an ASP.Net web application running on IIS6 that manages its own database of users.
The site itself just allows anonymous access and all authentication/security is managed using our application itself.
We have a page that contains an HTML table of data that we import into Excel and is then used for Reporting purposes. The page currently has no security implemented.
We need to add security to this page so that should these spreadsheets fall into the wrong hands then the data cannot be "Refreshed" without supplying a username / password.
If I set this page to not allow Anonymouse access then I can use Basic/Windows authentication with Windows Users in order to secure this page. Then when Excel refreshes the data the password dialog box pops up.
The problem is that I need to be able to secure this page based on the Users within our database and they will not be Windows users. I also need to do it in such a way that allows Excel to manage the authentication which excludes any Form based authentication.
Anyone got any ideas? Is it possible to get IIS to look elsewhere for it's Basic Authentication?
Ok, so I've found two solutions to this problem. One thanks to Zhaph - Ben Duguid's answer which is an HttpModule that allows ASP.Net to fully manage the authentication.
The second solution, and the one that I am going with, is thanks to this question/answer.
HTTP Authentication (Basic or Digest) in ASP Classic via IIS
I've stripped this down and have a simple test harness that seems to be working well. In this example, instead of a database call, it merely checks that the username and password match and considers that authenticated.
using System;
using System.Text;
namespace AuthenticationTests
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string authorisationHeader = Request.ServerVariables["HTTP_AUTHORIZATION"];
if (authorisationHeader != null && authorisationHeader.StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
{
string authorizationParameters = Encoding.Default.GetString(Convert.FromBase64String(authorisationHeader.Substring("Basic ".Length)));
string userName = authorizationParameters.Split(':')[0];
string password = authorizationParameters.Split(':')[1];
if (userName == password) //Perform your actual "login" check here.
{
//Authorised!
//Page loads as normal.
}
else
{
Unauthorised();
}
}
else
{
Unauthorised();
}
}
private void Unauthorised()
{
Response.AddHeader("WWW-Authenticate", "Basic");
Response.Status = "401 Unauthorized";
Response.End();
}
}
}
As you've got a custom database of users, I'd recommend looking at building a quick membership provider that talks to your database schema.
MSDN has a good example on "How to: Sample Membership Provider".
You can then use the standard access control mechanisms of ASP.NET to lock down the page, require authentication, etc, along with controls like Login, LoginStatus and others to provide much of the UI you need.
Edit to add
A quick search found the following, which might help:
Web Service Security - Basic HTTP Authentication without Active Directory
Where Greg Reinacker presents "a fully working sample in 100% managed code demonstrating the use of HTTP Basic authentication, using a separate credential store (in this case, a XML file, although this would be easy to change to a database or LDAP store)."
I'm not an expert but I thought that the point of Basic was that it was Windows Authentication. Can you run a script to synchronise your DB users with your Active Directory?
If it's a corporate AD, you could consider having a second AD just for your app and synchronising users from both your corporate AD and your DB. If you don't need to synchronise passwords (e.g. build a pwd-mgmt page in your site) you could just use scripts or C# or something. If you want something more sophisticated with built-in password synchronisation, you could look at ILM 2007 (soon to be FIM 2010).
Is the page an .html file or an .aspx file?
If it's an .aspx, you should keep this page under anonymous access and check for authentication in the page logic itself
I've written a library named FSCAuth that may help with this. It trivially can be set up for just basic authentication without Active Directory. It will instead read your user data out of a database/file/wherever(there is even a memory-only UserStore)
It is BSD licensed at Binpress