I want a way to implement 2 factor authentication. When the user enters their username and password it moves them to another page where they are granted a temporary Role and then they are asked to enter a security token which will be sent to them via email. authtoken image
login image
I have been there and I discovered that its pretty easy to implement this mostly in custom code if you are in conventional old school web app. I think there is something in spring that allows you to do this, but depending on your application it might be just so much easier to do this by yourself and not even that difficult.
One way is to create grails filter that covers all routes that are affected by this. For example all except login page and the second page after that. This filter will check the temp role and if found, it will redirect to the second auth page. Otherwise it lets the request pass. Could be something like this:
twoFactorCheck(controller: '*', controllerExclude: 'privacyPolicy|login|logout|2factor', action: '*') {
before = {
if (process2factorAuthNeed()) {
return true;
}
redirect(controller: "2factor", action: "index");
return false;
}
}
Then another thing you need is an implementation of custom UserDetailsService where you can capture the first normal authentication and set the temp role for the user. This is covered here: https://grails-plugins.github.io/grails-spring-security-core/2.0.x/guide/userDetailsService.html if you are on grails 2.* but your spring security plugins version user guide will have this entry as well.
Related
I am creating web application using ASP.NET MVC5 framework with 'windows authentication' - i.e. I am creating an intranet application authenticating users against active directory.
When new user is defined in company's active directory, I'd need to catch his first login and redirect him onto profile page, where user is prompted to fill some info.
I am able to catch user's first login by simple look into the database, if the user has here his own record in some table. If not, the user is here first time and I can create him such record.
Here comes the deal - after extensive searching through possibilities it seems the only "reasonable" way how to do it is via custom AuthenticationFilter - specifically to put the DB check logic into
OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
method.
The reason why I put "reasonable" into the quotes is that on one hand, this approach fits into the MVC philosophy - by which I mean that it is not some 'hack' approach.
On the other hand - since I am using windows authentication, there is effectively no Login action in any controller. User can type whatever 'www.mysite.com/controller/action' url and if not logged in, there is no redirect to login page, the windows security box just appears prompting for credentials. Which means that I have to register my custom authentication filter globally to cover all controller/action patterns. That would mean that the DB check would be performed each and every request - I don't like this. I am not sure how much performance hit this could make, but also it doesn't seem right from design point of view.
The last thing I've tried was to use my authentication filter to catch 'unauthenticated' users and redirect them to some 'Login' action - but here I found that the windows security box is appearing before even the authentication filter is fired, so technically my custom authentication filter never catches an unauthenticated user.
So my question is - is there a better approach how to step in the logging process with one time action? Or I can use what I have - i.e. globally registered authentication filter performing DB check every request ?
Thanks
Finally I have some working solution for this.
The problem:
MVC5 APS.NET intranet application using windows authentication. After successful login against active directory we want to find out if the user is here for the first time and if so, create him record in application database.
The solution:
Since I am at the end of the day interested only in authenticated and authorized users I've created a globally registered action filter i.e. filter which will be applied to every single controller/action combination after successful authentication/authorization.
Inside this filter I am checking if the current session has flag IsNewSession set to true. If so, I am performing that check against application DB. That way even if the action filter is invoked each request I am doing roundtrip into database only once - during user's first request.
The implementation:
public class DbCheckFilter : ActionFilterAttribute
{
private AppDbContext db = new AppDbContext();
//we are overriding OnActionExecuting method since this one
//is executed prior the controller action method itself
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//is this a new session
if (filterContext.HttpContext.Session.IsNewSession)
{
//we are storing users in db based on their active directory
//Guid - therefore we need to get 'UserPrincipal' object
//instead of 'WindowsPrincipal' provided by filterContext
using (var principalContext = new PrincipalContext(ContextType.Domain))
{
var principal = UserPrincipal.FindByIdentity(principalContext, filterContext.HttpContext.User.Identity.Name);
if (principal != null)
{
//finally we perform the DB check itself
if (!CreateUserInDbIfNew(principal.Guid.Value, principal.DisplayName))
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
else
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
base.OnActionExecuting(filterContext);
}
I believe this is what you're looking for. Your db check will only happen once at this point. You can add this method to your Global.asax like so, which works with Windows Auth once authorized...
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
// Do your check here
// Do something
}
I have a Domain class and Controller called Person. This Controller has 4 views. create.gsp, remove.gsp, show.gsp, showdetail.gsp.
What i want to do is to allows read permission for showdetail.gsp to all viewers and restrict access to create.gsp, remove.gsp and show.gsp views. Only the Administrator should be able to access these pages. How can i do this in Grails?
You can use security filters to do that or you can use Spring Security Core grails plugin.
If you can want to use security filters, you can do the following:
Create session for each user at the time of login.
session["user"] = "rohit" // user name
Add security Filters:
PersonFilters(controller: 'person', action: 'create') {
before = {
// code to be change
if(!session["user"]) {
//flash.message = "Your session has been expired. Please login to continue."
redirect(controller: "login", action:"index")
return false;
} else if(session["user"] && session["user"] != "admin"){
// redirect to some action
// redirect(controller: "", action:"index")
return false;
}
}
}
Similarly, you can add security filter for those actions that you don't want to show to any user except the admin.
First of all, user would need to login and after successful authentication, session should be maintained properly. And then in controller filter, you could write an interceptor which can allow access to certain actions based on authorization rules.
All these and much more is already done along with UI part in nimble plugin, it is very easy.
And read this document:
http://snimavat.github.io/nimble/guide/leverage.html#accesscontrol
What is the best practice or approach to get lastvisited information for an user in Grails? For user login, I am using spring security and I want to show few junks of information based on lastvisited date. So far I don't have any property in user domain. Would you please let me know different and possible approaches that i can easily collect aforementioned information within Grails application. Another related query is, how can i combat with aforementioned problem when a user closes a window or tab in browser without pressing logout link/button?
We ended up pretty messy - will be happy to know a better way. We're saving visit info of:
login - in an action that spring-security-redirect points to;
login by "remember me" - in ApplicationListener.onApplicationEvent(appEvent) (we made a service an ApplicationListener):
if (appEvent instanceof AuthenticationSuccessEvent) {
if (appEvent.source instanceof RememberMeAuthenticationToken) {
}
}
Maybe this is the place to collect all the login events.
logout - in our own logout action that redirects to j_spring_security_logout.
we don't log session timeouts.
I am creating my own website and blog and I want for first time just me in database (my name and password) and maybe later some registration for others but first log in just for me and administration with authorization. I don´t want to use Membership from MS. I want try to create my own from start so I am looking for guide for beginners but I found big guides with roles, rights. I want just small example with check username, password in database with log on data.
Thanks for help
Libor
Even if you don't want to use the membership and role provider data store you can still utilize the authentication. Trust me, it's a lot easier than building your own. Here's how it works:
We'll say you already have your user storage setup for retrieving the username and their password. For the sake of simplicity I'm going to pretend you have a static class called DataLayer that contains your data retrieval methods for pulling info from the database (or whatever storage you use).
First you need a way to let the user log in. So set up a page with username and password fields. Then in the action method that the page posts to set up a quick if statement:
if (DataLayer.UserExists(userModel.Username))
{
User userFromDB = DataLayer.GetUser(userModel.Username);
if (userFromDB.Password == userModel.Password)
{
FormsAuthentication.SetAuthCookie(userFromDB.Username, checkBoxRememberMe.Checked);
//Use userFromDB as the username to authenticate because it will
//preserve capitalization of their username the way they entered it
//into the database; that way, if they registered as "Bob" but they
//type in "bob" in the login field, they will still be authenticated
//as "Bob" so their comments on your blogs will show their name
//the way they intended it to.
return "Successfully logged in!";
}
}
return "Invalid username or password.";
Now that they are authenticated you can just use Page.User.Identity.IsAuthenticated in your code to find out if they are logged in. LIke this:
if (User.Identity.IsAuthenticated)
{
DataLayer.PostBlogComment(User.Identity.Name, commentBody);
//Then in your controller that renders blog comments you would obviously
//have some logic to get the user from storage by the username, then pull
//their avatar and any other useful information to display along side the
//blog comment. This is just an example.
}
In addition, you can lock out entire action methods or even whole controllers to users that are authenticated through the forms authentication provider. All you have to do is add tags like these to your action methods/controllers:
[Authorize]
public ActionResult SomeActionMethod()
{
return View();
}
The [Authorize] attribute will prevent users that are not logged in from accessing that action method and it will redirect them to your login page. You can use this same attribute to filter out roles if you are using the built in roles provider.
[Authorize(Roles="Admin, SalesReps")]
public ActionResult SomeActionMethod()
{
return View();
}
These attributes can also be added above the controller class to apply it's logic to the entire controller.
EDIT: To log a user out all you need to do is call FormsAuthentication.SignOut();
Hey #Bibo, good for not choosing the Membership providers. I think a UserService or similar which provides methods for creating, authenticating users and some few more methods should be enough. As a suggestion, use password hashing and a password salt for the user´s password. Here is a good link to look at. Also have a look at this answer I gave some time ago.
Good luck!
EDIT: The rememberMe parameter should be named keepMeSignedIn instead.
This article on forms authentication gives you loads of info for creating your own simple security system, especially the bit about FormsAuthenticationTicket.
http://support.microsoft.com/kb/301240
I am using successfully custom authorization in ASP.NET MVC. It simply involves a comparison between User.Identity and the owner of the object in context.
It works like a charm when used in simple conditions. It becomes more complicated when I try to call 2 actions in one web request.
Lets say I want to display an image which would be generated on-the-fly by my application. This image is generated by a controller, thus, it can be referenced by an URL even if it doesn't exist physically. I have decided that the user must be signed in and be the owner to view it, so I apply my authorization mechanizm to it.
Example: <img src="http://myapplication.com/images/generate/3" />
When I include such an image in a page via its action hyperlink, I expect that the authenticated user will still be in context on server side when the image is generating. This is not the case in my tests. The image never displays because my authorization check doesn't work. In the image controller, User.Identity is empty as if the user has not signed it.
In the meantime, the same user is still signed in to the website and can continue to browse with his identity in context... without those images working properly.
I wonder how to make this process work securely...
Thank you very much!
Marc Lacoursiere
RooSoft Computing inc.
Just wondering if you've checked if
Thread.CurrentPrincipal
is also empty in the controller? It should contain the same value.
Another suggestion would be to store the User.Identity value in a session?
You need to set up your identity in global.asax on every request. I'm using a custom Principal and Identity for this.
private void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (!Request.IsAuthenticated)
{
SetIdentity(new MyIdentity
{ Type = UserType.Inactive, Id = int.MinValue });
}
else
{
HttpCookie authCookie = Request.Cookies[
FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket =
FormsAuthentication.Decrypt(authCookie.Value);
var identity = Repository.GetIdentity
(authTicket.Name, new HttpRequestWrapper(Request));
SetIdentity(identity);
}
}
}
private void SetIdentity(MyIdentity identity)
{
Context.User = new MyPrincipal { Identity = identity };
Thread.CurrentPrincipal = Context.User;
}
This works, but I don't guarantee it to be secure. You should review this article on FormsAuthentication vulnerabilities prior to going live with this code. You have to understand that this code assumes the cookie is valid and hasn't been hijacked. There are some additional security measures that can be taken to reduce these vulnerabilities which this code doesn't show.
This may be when the site link in browser is http:\www.mysite.com (or http:\subdomain.mysite.com ) and you are using http:\mysite.com\image\5 in your application. Form authentication uses cookies. And these cookies may belong to domains and subdomains.
To find out what is going on I suggest to use FireFox with FireBug installed. Enable Net and Console tab for your site and make a complete refresh of the page. After you'll see requests in one of these tabs (Net tab exactly). At the left of the request you can see 'a plus' button, after you click it you'll see Headers and Response tabs (more detailed description of firebug). Have a look at Headers tab and try to find something like FORMAUTH (or what you've set in config as a forms cookie name). If you not see it - the problem is in domains.