I am new to Nancy and .NET framework. here I am running in a panic situation.
I have written my own Bootstrapper to enable CookieBasedSessions in project.Here are tasks i have to perform.
Once user logged in create session and set User in session.
Then on each request verify the user in session
class Bootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
CookieBasedSessions.Enable(pipelines);
}
}
Here is my controller.
Post["/myapp/login"] = parameters =>
{
var model = new User();
model.UserName = this.Request.Form.userName;
model = manager.GetUser(model.UserName);
if (!string.IsNullOrEmpty(model.UserName) && model.isAdmin())
{
// var user = Request.Session["user"];
if (Request.Session["key"] != null) // Here i get the ERROR
Request.Session["key"] = model;
return Response.AsRedirect(HOME_URL);
}
else
return Response.AsRedirect(LOGIN_URL);
};
when I execute this code I am getting {"Session support is not enabled."} error.
Any help is appreciated.
It's not using your custom bootstrapper - make the class public and it will pick it up.
Related
Here is my code. I have written login to validate the token, for valid token return user object. but unable to find way to make it available across controllers.
I don't want to use Identity.
public class CustomAuthorize : AuthorizeAttribute
{
private const string AUTH_TOKEN = "AuthToken";
public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
AllowAnonymousAttribute allowAnonymousAttribute = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().FirstOrDefault();
if (allowAnonymousAttribute != null)
{
return Task.FromResult<object>(null);
}
if (actionContext.Request.Headers.Contains(AUTH_TOKEN))
{
var authToken = actionContext.Request.Headers.GetValues(AUTH_TOKEN).First();
var user = Utility.GetUserByToken(authToken);
if (user != null)
{
//
// how to make this `user` object available across the controllers
//
return Task.FromResult<object>(null);
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new CustomError() { Code = 100, Message = "Invalid Access Token" });
return Task.FromResult<object>(null);
}
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new CustomError() { Code = 100, Message = "Invalid Access Token" });
return Task.FromResult<object>(null);
}
}
}
Please help...
Your Question is a bit unclear - I assume you are referring to this line:
var user = Utility.GetUserByToken(authToken);
If so, then I might have a solution. So the fundamental problem is that you cannot simply save this variable where you currently are in the current controller, you need to understand the context you are working in - Every time a different user makes a request a different user models get created in the current controller. To have access to the user model across my app whenever a user makes a request, I do the following:
First you need to hook into the request receiving process of ASP.NET. This can be done inside the Global.asax.cs file, but I prefer to keep it clean and create a PartialGlobal class and mark the Global.asax.cs as partial.
From
public class MvcApplication : System.Web.HttpApplication
To
public partial class MvcApplication : System.Web.HttpApplication
Then create the PartialGlobal Class:
public partial class MvcApplication
{
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
//For API users
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
if (authHeaderVal.Scheme.Equals("Basic", StringComparison.OrdinalIgnoreCase))
{
if (!string.IsNullOrEmpty(authHeaderVal.Parameter))
{
AuthenticateUser(authHeaderVal.Parameter);
}
}
}
//For Regular Website Users
else
{
HttpCookie authCookie = request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
//Extract the forms authentication cookie
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
// If caching userData field then extract
var userModel = UsersBLL.DeserializeObject(authTicket.UserData);
var principal = new UserPrincipal(userModel);
SetPrincipal(principal);
}
}
}
private static bool AuthenticateUser(string credentials)
{
var model = UsersBLL.DecryptToken(credentials);
if (!model.RefUser.HasValue)
{
return false;
}
SetPrincipal(new UserPrincipal(model));
return true;
}
private static void SetPrincipal(UserPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
}
The UserPrincipal Class:
public class UserPrincipal : IPrincipal
{
public IIdentity Identity { get; private set; }
//Just a class with details like name,age etc.
public UserModel Model { get; set; }
public UserPrincipal(UserModel model)
{
this.Model = model;
this.Identity = new GenericIdentity(model.Email);
}
}
Note the line in the PartialGLobal class: var model = UsersBLL.DecryptToken(credentials);. Here I simply use a method I created to de-crypt my token string so it can be deserialized, you probably won't have/need this.
The essential part is this last step of the PartialGlobal class:
private static void SetPrincipal(UserPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
If you have the context know about your user, you can access it anywhere by simply calling:
var principal = (UserPrincipal)HttpContext.Current.User;
One way is to Extend the ApiController which is what your controllers are using as the base class.
Define a CustomController
public class CustomController : ApiController
{
projected User _user;
}
For all the other controller use this as a base class and the _user object should be accessible from all the controllers.
I have an MVC 5 data first app that I've been helping with. I made it use a filter to determine if the AD user is allowed certain functionality (via decorating methods/classes).
However, after changing a user's info in the db, the filter's context still has the old info for that user. The user 'edit' page keeps correct info though. Strange. This is happening just in the filter, not in any controller.
Here's the filter:
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (!base.AuthorizeCore(httpContext)) return false;
// Get the groups for this authorization (from the decoration attribute)
var groups = Groups.Split(',').ToList();
var userDisplayName = string.Empty;
using (HostingEnvironment.Impersonate())
{
// Verify that the user is in the given AD group (if any)
var context = new PrincipalContext(
ContextType.Domain);
var userPrincipal = UserPrincipal.FindByIdentity(
context,
IdentityType.SamAccountName,
httpContext.User.Identity.Name);
userDisplayName = userPrincipal.DisplayName;
}
// check for UserRoles for this
var user = _varDB.Users.FirstOrDefault(x => x.UserName == userDisplayName); //< Here is where it gets stale info...
IList<UserRole> usersRoles = new List<UserRole>();
if (user != null)
{
usersRoles = user.UserRoles.ToList();
}
// determine if the user is allowed to see this controller/page
foreach (var ur in usersRoles)
{
if (groups.Contains(ur.RoleName))
{
return true;
}
}
return false;
}
On the UserController, if I manually change the db, and refresh the page, I see the changes. But in this filter, if I change the data, it never changes until I recycle the app pool.
fyi, the top of the class goes like this:
public class AuthorizeByDbRoleAttribute : AuthorizeAttribute
{
private static ExtVariablesEntities _varDB = new ExtVariablesEntities();
}
If this filter doesn't get the updated user info, it can't keep users out of or let them use functionality if changed and the app pool isn't recycled.
Problem was that a class that inherits from AuthorizeAttribute (or any attribute I believe) the class doesn't dispose of the context. I wound up wrapping the logic in a using like this:
using (ExtVariablesEntities _varDB = new ExtVariablesEntities())
{
// check for UserRoles for this
var user = _varDB.Users.FirstOrDefault(x => x.UserName == userDisplayName);
IList<UserRole> usersRoles = new List<UserRole>();
if (user != null)
{
usersRoles = user.UserRoles.ToList();
}
// determine if the user is allowed to see this controller/page
foreach (var ur in usersRoles)
{
if (groups.Contains(ur.RoleName))
{
return true;
}
}
}
This was the context get created each time this class method is hit.
Is there any way to hook into (I want to perform a check for certain conditions directly after login) the login process in ASP.NET MVC4. I am using the default MemberShip classes provided by Visual Studio.
Yes, you can create your on AuthorizeAttribute and implement your login on OnAuthorization method.
Here's a sample:
public class AuthenticateAndAuthorizeAcsMvcAttribute : System.Web.Mvc.AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
var principal = filterContext.HttpContext.User;
if (principal == null || !principal.Identity.IsAuthenticated)
{
filterContext.Result = new ViewResult()
{
ViewName = "AcsLogin",
ViewData = filterContext.Controller.ViewData,
TempData = filterContext.Controller.TempData
};
return;
}
base.OnAuthorization(filterContext);
}
}
I'm currently using the ASP.NET Web Api along with NHibernate & Autofac...I'm having an issue where my update is not being committed to the database. I'm using an ActionFilterAttribute to open and close a transcation every time an action is performed like so:
private ISessionFactory SessionFactory { get; set; }
public TransactionAttribute()
{
SessionFactory = WebApiApplication.SessionFactory;
}
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var session = SessionFactory.GetCurrentSession();
var transcation = session.Transaction;
if (transcation != null && transcation.IsActive)
{
transcation.Commit();
}
session = CurrentSessionContext.Unbind(SessionFactory);
session.Close();
}
Which works fine for the add, read, and delete functions in my repository. Unfortunately, my update doesn't seem to be working (though I've tried it several ways):
public bool Update(Client client)
{
var result = Get(client.ClientID);
if (result == null)
{
return false;
}
result.Name = client.Name;
result.Acronym = client.Acronym;
result.Website = client.Website;
return true;
}
From what I've read if modifying an object during a transaction, there's no need to manually call Update or SaveOrUpdate, as this is tracked by NHibernate & performed when the transaction is committed.
Why would my update function not be working properly?
Thanks!
I figured this out on my own--basically I was creating 2 sessions (one in my TranscationAttribute and one due to DI into my repository). The reason it was creating two is pretty explicit in the OnActionExecuting statement...I'm not checking to see whether any session factory is currently bound to the CurrentSessionContext. This is the new code I'm using:
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!CurrentSessionContext.HasBind(SessionFactory))
{
CurrentSessionContext.Bind(SessionFactory.OpenSession());
}
var session = SessionFactory.GetCurrentSession();
session.BeginTransaction();
}
The issue I had after implementing this code is that the logic is not sound..when the session is DI'ed into my repository ISession, it was not being automatically bound. My solution was to bind it in the constructor of my repository like so:
public ClientRepository(ISession session)
{
if (session == null) throw new ArgumentNullException("nhSession");
this._session = session;
CurrentSessionContext.Bind(_session);
}
But I'm not 100% sure that this is going to be safe with many simultaneous HTTP requests...going to bring this question over to code review unless someone has an answer for me here!
Thanks!
I am building a system where some users have access to certain pieces of data and not others.
How do I secure my application so that user A can get access to
/Product/1/Edit but not /Product/2/Edit
I was thinking of using an action filter for this. Is this the right way to do it?
Yes, a custom Authorize action filter is a good place to do this. Here's how you could proceed:
public class MyCustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!(filterContext.Result is HttpUnauthorizedResult))
{
var currentUser = filterContext.HttpContext.User.Identity.Name;
var currentAction = filterContext.RouteData.GetRequiredString("action");
var id = filterContext.RouteData.Values["id"];
if (!HasAccess(currentAction, currentUser, id))
{
HandleUnauthorizedRequest(filterContext);
}
}
}
private bool HasAccess(string currentAction, string currentUser, object id)
{
// TODO: decide whether this user is allowed to access this id on this action
throw new NotImplementedException();
}
}