Using OWIN to authorize classic ASP pages - asp-classic

I have an ancient Classic ASP website that used to use Windows authentication for access control but this is no longer appropriate. I thought I might try and wrap this website in an ASP.NET MVC 5 app, so I:
created a new website complete with ASP.NET Identity
created a user
copied the Classic ASP website into the root
viewed the classic ASP website
Now what I need to do is require authorization for all .asp pages so that only authorized users can see them. What's the best way of doing this? Maybe I could do something with OWIN?
Crispin

Following this example I created an HttpModule that came out like this:
public class ClassicAspAuthorization : IHttpModule
{
private MyEventHandler _eventHandler = null;
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
}
public delegate void MyEventHandler(Object s, EventArgs e);
public event MyEventHandler MyEvent
{
add { _eventHandler += value; }
remove { _eventHandler -= value; }
}
public void OnBeginRequest(Object s, EventArgs e)
{
HttpApplication app = s as HttpApplication;
if (app.Request.CurrentExecutionFilePathExtension.EndsWith(".asp") == true && blnIsAuthenticated() == false)
{
app.Context.Response.Redirect("/Account/Login");
}
if (_eventHandler != null)
{
_eventHandler(this, null);
}
}
and the boolean (blnIsAuthenticated) method that determined whether or not the user was authenticated was derived from a Stackoverflow answer where I removed the lines:
var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
var principal = new ClaimsPrincipal(identity);
System.Threading.Thread.CurrentPrincipal = principal;
HttpContext.Current.User = principal;
and replaced this with my own claims checking to establish if the user was authenticated. An appropriate boolean value was returned.

Related

Where to read Forms authentication cookie?

I have implemented Forms authentication in one project. In the forms authentication cookie I store the Login Id of the user. i.e.
FormsAuthentication.SetAuthCookie(LoginId, false);
I now need to read the cookie value on every request to get more information about the user and put this information in the HttpContext.Items property. The project is a MVC project that has both regular MVC Controllers as well as Web API controllers. Currently I have created two action filters - one for the MVC controllers and other for Web API Controllers where I read this value. So like
public class MyMvcFilter : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
var ticket = FormsAuthentication.Decrypt(cookie.Value);
filterContext.HttpContext.Items.Add("LoginId",ticket.Name);
}
base.OnAuthorization(filterContext);
}
}
and
public class MyFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
base.OnActionExecuting(actionContext);
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie == null)
{
return;
}
var ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket == null)
{
return;
}
actionContext.Request.Properties.Add("LoginId", userId);
}
}
However the more I think of it, the more it looks like an ugly hack to me. What would be correct location where I can decrypt the authentication cookie and remains the same for MVC controller as well as Web API controller ?
I would:
Read the cookie on the
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
}
In the above method....Convert the cookie to a ClaimsPrincipal.
Like the below:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
IList<Claim> claimCollection = new List<Claim>
{
new Claim("http://www.mycompany.com/claims/LoginId, "123456" /* use info from cookie instead of 123456*/)
};
ClaimsIdentity claimsIdentity = new ClaimsIdentity(claimCollection, "My e-commerce website");
Console.WriteLine(claimsIdentity.IsAuthenticated);
ClaimsPrincipal customPrinc = new ClaimsPrincipal(claimsIdentity);
if (null != customPrinc)
{
Thread.CurrentPrincipal = customPrinc; /* Set here. But when you need to "get" it, use "System.Security.Claims.ClaimsPrincipal.Current" */
/* ASP.NET Authorization depends on value of HttpContext.Current.User.
* Consider putting ClaimsPrincipal into both HttpContext.Current.User and Thread.CurrentPrincipal */
HttpContext.Current.User = customPrinc;
/* Note the second setter is necessary so you don't lose it later on, learned the hard way by experience */
}
}
Retrieve the Claims Principal as needed..
/* MVC */
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
/* the below should be what you set in the Application_PostAuthenticateRequest method */
IPrincipal currentClaimsPrinc = ClaimsPrincipal.Current;
}
/* WebAPI */
public override void OnAuthorization(HttpActionContext actionContext)
{
IPrincipal claimsPrincCurrent = ClaimsPrincipal.Current;
}
You could also do this:
adding claims to forms authentication in asp.net
or this:
http://brockallen.com/2013/01/26/replacing-forms-authentication-with-wifs-session-authentication-module-sam-to-enable-claims-aware-identity/
or this:
http://chris.59north.com/post/Claims-based-identities-in-ASPNET-MVC-45-using-the-standard-ASPNET-providers
MVC and WebAPI (until .NET Core) do not share the same pipeline so you need to use two different filters.
What you can do is share the code, if you want, maybe with an utility method or something. Just to avoid having two codes doing the same stuff

Adding custom roles to windows roles in ASP.NET MVC 5

I'm building an intranet app using ASP.NET MVC 5.
My goal is to have the authentication of any user made by the Active Directory (i.e. I'm using the "Windows Authentication"), then add groups to any user inside the application (NOT using domain groups).
I've found some very interesting piece of code here:
http://brockallen.com/2013/01/17/adding-custom-roles-to-windows-roles-in-asp-net-using-claims/
But it's not working in my scenario: when I decorate the controller with [Authorize(Role="AppRole")], I can't be authorized even if the user (using Claims) is associated with the "AppRole" role.
This is my code:
In Global.asax.cs
void Application_PostAuthenticateRequest()
{
if (Request.IsAuthenticated)
{
string[] roles = Utils.GetRolesForUser(User.Identity.Name);
var id = ClaimsPrincipal.Current.Identities.First();
foreach (var role in roles)
{
//id.AddClaim(new Claim(ClaimTypes.Role, role.ToString()));
id.AddClaim(new Claim(ClaimTypes.Role, #"Kairos.mil\Compliance"));
}
bool pippo = User.IsInRole("Compliance");
HttpContext.Current.User = (IPrincipal)id ;
bool pippo2 = User.IsInRole("Compliance");
}
}
The function GetRolesForUser is as follows (and is working fine):
public static string[] GetRolesForUser(string username)
{
dbOrdiniPersonaliEntities db = new dbOrdiniPersonaliEntities();
string utente = StripDomain(username);
string[] gruppi = new string[db.vGruppiUtentis.Where(t => t.KairosLogin == utente).Count()];
int i=0;
foreach (var gruppo in db.vGruppiUtentis.Where(t => t.KairosLogin == utente))
{
gruppi[i]=gruppo.GruppoDes;
i=i++;
}
return gruppi;
}
And the controller is decorated with the "standard" Authorize clause:
[Authorize(Roles="AppRole")]
public ActionResult Index(string sortOrder, string currentFilter, string DesSearchString,int? page)
{
// my code here
}
Any idea?
Thanks in advance
UPDATE
Thanks #Leandro
I've tried as you suggested the following code
void Application_PostAuthenticateRequest()
{
if (Request.IsAuthenticated)
{
string[] roles = Utils.GetRolesForUser(User.Identity.Name);
ClaimsIdentity id = ClaimsPrincipal.Current.Identities.First();
foreach (var role in roles)
{
//id.AddClaim(new Claim(ClaimTypes.Role, role.ToString()));
id.AddClaim(new Claim(ClaimTypes.Role, #"Kairos.mil\Compliance"));
}
bool pippo = User.IsInRole("Compliance");
SetPrincipal((IPrincipal)id);
bool pippo2 = User.IsInRole("Compliance");
}
}
But I receive a run-time error when the code reaches this point
SetPrincipal((IPrincipal)id);
The error is as follows
Unable to cast object of type 'System.Security.Principal.WindowsIdentity' to type 'System.Security.Principal.IPrincipal'.
Thanks for your help
UPDATE 2 (maybe solved)
Hi
Looking deeper into SO, I've found this resource
ASP.NET MVC and Windows Authentication with custom roles
Following the answer of #Xhalent, I modified my code as follows
protected void Application_PostAuthenticateRequest()
{
if (Request.IsAuthenticated)
{
String[] roles = Utils.GetRolesForUser(User.Identity.Name);
GenericPrincipal principal = new GenericPrincipal(User.Identity, roles);
Thread.CurrentPrincipal = HttpContext.Current.User = principal;
}
}
It seems now working fine! Any comments? Any drawbacks? Thanks a lot!!
Use this method to save the principal, so it sets up also in the thread:
private void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
Update: Also allow anonymous and test if User.IsInRole is getting something inside the method.

How to Authorize user in controller action using list of user from database in ASP.NET MVC 4?

i am doing this in order to authorize user.
[Authorize(Users = #"user1, user2, user3")]
public class MyController : Controller
{
// my stuff
}
i want to do authorization from the list of user which are in database table..
This is how I got it done:
Create a new class (which inherits from AuthorizeAttribute class).
public class CustomAuthorizeAttribute : AuthorizeAttribute
Override the AuthorizeCore method (in CustomAuthorizeAttribute class) and include your custom logic in it.
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isUserAuthorized = false;
// custom logic goes here
// You can get the details of the user making the call using httpContext
// (httpContext.User.Identity.Name)
// Then get the information you have stored on your db, and compare it
// with these details.
// Set isUserAuthorized to true if the values match
return isUserAuthorized;
}
Decorate your controller action method with the attribute that you just created.
[CustomAuthorize]
public ActionResult DoSomething(string something, string someOtherThing)
This link form Gotalove is helpful.
try the following:
"using the link shared by #VikasRana http://www.codeproject.com/Articles/578374/AplusBeginner-splusTutorialplusonplusCustomplusF
I got rid of my enum Role and my method
public CustomAuthorizeAttribute(params object[] roles)
{ ...}
I then changed Role in my model to be a string e.g. User.Role="Admin" instead of int. In my onAuthorization method I changed it to:
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.TempData["ErrorDetails"] = "You must be logged in to access this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Controller.TempData["ErrorDetails"] = "You don't have access rights to this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
}
and in my global.asax added this.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true && Request.IsAuthenticated== true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (GManagerDBEntities db = new GManagerDBEntities())
{
User user = db.Users.SingleOrDefault(u => u.Username == username);
roles = user.Role;
}
//let us extract the roles from our own custom cookie
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//something went wrong
}
}
}
}
"
Source: Custom user authorization based with roles in asp.net mvc
PS.: In this link, in the same post, there is a second way to fix your problem.
In the bottom of the post.
If this can't to help you, you should try it to.

Basic authentication IHttpModule unexpected behaviour

I have enabled Basic Authentication in IIS7 for my site and followed this link to create handler for basic authentication requests.
The problem is that no matter what credentials user enters, the site keeps returning 401, even if entering correct credentials. This is just a test and credentials are checked against hardcoded values.
Here is relevant code:
public class BasicAuthenticationHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest+=context_BeginRequest;
context.AuthenticateRequest += context_AuthenticateRequest;
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
TryAuthenticate(application);
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
TryAuthenticate(application);
}
private static void TryAuthenticate(HttpApplication application)
{
if (!Authenticate(application.Context))
{
application.Context.Response.Status = "401 Unauthorized";
application.Context.Response.StatusCode = 401;
application.Context.Response.AddHeader("WWW-Authenticate", "Basic");
application.CompleteRequest();
}
}
private static bool Authenticate(HttpContext context)
{
if (context.User!=null && context.User.Identity.IsAuthenticated)
{
return true;
}
if (!context.Request.Headers.AllKeys.Contains("Authorization"))
return false;
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
IPrincipal principal;
if (TryGetPrincipal(authHeader, out principal))
{
context.User = principal;
return true;
}
return false;
}
private static bool TryGetPrincipal(string[] creds, out IPrincipal principal)
{
if (creds[0] == "Administrator" && creds[1] == "SecurePassword")
{
principal = new GenericPrincipal(
new GenericIdentity("Administrator"),
new string[] { "Administrator", "User" }
);
return true;
}
if (creds[0] == "BasicUser" && creds[1] == "Password")
{
principal = new GenericPrincipal(
new GenericIdentity("BasicUser"),
new string[] { "User", "SystemUser" }
);
return true;
}
else
{
principal = null;
return false;
}
}
When client enters correct credentials (i.e. "BasicUser", "Password"), GenericPrincipal object is created and assigned to HttpContext's User property. Looking into Request.IsAuthenticated tells that it's true.
And this is why I don't understand is why client receives 401 again and again and again.
I'm not sure how all the pipeline works - may be basic authentication goes further to some IIS HttpModule which also serves the request? Or may be code is incomplete and context_BeginRequest needs to be extended? (I know that in case of Forms authentication type, you do something like Response.Redirect(goodguy.aspx))
Anyway, any help/questions are appreciated.
Forgot to mention that in web.config I also placed
<system.webServer>
<modules>
<add name="BasicAuthenticationHttpModule" type="Analytics.BasicAuthenticationHttpModule" />
</modules>
</system.webServer>
Apparently implemements it's own Basic authentication. Thus our module could authenticate request succussfully, it would get passed to built-in IIS module, which rejected authentication. It is really helpful not to copy paste, but also to think yourself indeed. So to answer my question - disable all authentication on IIS except Anonymous.

How to get login text boxes values in HTTP Module in asp.net 2.0?

I am making a Http Module for authentication in my web application in asp.net 2.0. When the AuthticateRequest event is fired then I get the userid and password values from current request. But Every time I am getting null in both. My code is here
namespace Business.YouBecome
{
class LoginModuleYouBecome : IHttpModule
{
public void Init(HttpApplication httpApplication)
{
httpApplication.AuthenticateRequest += new EventHandler(httpApplication_AuthenticateRequest);
// httpApplication.AuthorizeRequest += new EventHandler(httpApplication_AuthorizeRequest);
}
void httpApplication_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = (HttpContext)application.Context;
clsLogin login = new clsLogin();
login.UserName = application.Request["txtuser"];
login.Password = application.Request["txtpass"];
//throw new NotImplementedException();
}
public void Dispose() { }
}
}
I have this class in a class library project and added the code in web.config.
Please suggest me where I am doing wrong. Thanks in advance.
try like this: in your event handler you should check if your user is authenticated and then use User.Identity to access name and password.
if (User.Identity.IsAuthenticated)
{
//...
login.UserName = User.Identity.Name;
login.Password = User.Identity.Password;
}

Resources