variables in the flash scope don't stay alive in Google Chrome - java

When a user tries to access a page in the administration controllers (mostly CRUD stuff), he is being redirected to the login page. And, if the credentials is correct and he is indeed an administrator, he is begin redirected to the page he wanted to access in the previous request.
Whenever someone tries to access a forbidden page he is being redirected to the following controller:
public static void login(String returnUrl) throws Throwable {
Http.Cookie remember = request.cookies.get("rememberme");
flash.put("url",returnUrl);
if (remember != null && remember.value.indexOf("-") > 0) {
String sign = remember.value.substring(0, remember.value.indexOf("-"));
String username = remember.value.substring(remember.value.indexOf("-") + 1);
if (Crypto.sign(username).equals(sign)) {
session.put("username", username);
redirectToOriginalURL(returnUrl);
}
}
flash.keep();
render();
}
Which executes the authenticte(...) method:
public static void authenticate(#Required String username, String password, boolean remember, String returnUrl) throws Throwable {
// Check tokens
Boolean allowed = false;
// This is the official method name
allowed = (Boolean) Security.invoke("authenticate", username, password);
if (validation.hasErrors() || !allowed) {
flash.keep("url");
flash.error("secure.error");
params.flash();
login(returnUrl);
}
// Mark user as connected
session.put("username", username);
// Remember if needed
if (remember) {
response.setCookie("rememberme", Crypto.sign(username) + "-" + username, "30d");
}
// Redirect to the original URL (or /)
flash.keep("url");
redirectToOriginalURL(returnUrl);
}
Note the String returnUrl in the parameter list. This controller is always called in the view with the response.url value.
The redirectToOriginalURL() is a method that receives a returnUrl in the parameter or in the flash scope.
static void redirectToOriginalURL(String returnUrl) throws Throwable {
if(returnUrl==null) returnUrl = flash.get("url");
if (returnUrl == null) {
returnUrl = "/";
}
redirect(returnUrl);
}
This works fine in Firefox and Internet Explorer. But when I try to execute this in Google Chrome, the returnUrl is null. Is this a known issue, or am I doing something terribly wrong?
There are no special requests or anything. The url, when redirected from the unaccessible page (localhost:9000/admin) is http://localhost:9000/account?returnUrl=%2Fadmin. So nothing wrong there...
The error must therefore lie withing the authenticate controller, that seems to be unable to pass arguments to the redirectToOriginalURL method. But, then again, only in Google Chrome.
Suggestions?

I got it working this way:
Make sure that checkAccess method calls login method with current url:
static void checkAccess() throws Throwable {
// Authent
if (!session.contains("username")) {
login(request.method.equals("GET") ? request.url : "/");
}
}
Then in login.html view add the hidden field which is the param you already passed to login method:
#{form #authenticate()}
<input type="hidden" name="returnUrl" value="${params.returnUrl}">
...
#{/form}
Or add returnUrl param directly to form.action:
#{form #authenticate().add("returnUrl", params.returnUrl)}
That's it. And you don't need flash scope.

I noticed this line of code in login:
redirectToOriginalURL();
That calling the method with no arguments, but the redirectToOriginalURL you show has a parameter String. Could it be this is part of the issue?

Related

Session existing even after invalidating it

I have basic login-logout session management problem.
When i click login button, this function below gets triggered.After LDAP authentication, it moves to index.html where I display their name.
function validate()
{
var pageTitle=$(document).attr('title');
var un=document.getElementById('username').value;
var pwd=document.getElementById('pass').value;
$.ajax({
'url':'/analytics_1/validate',
'data':'userName='+un+'&password='+pwd,
'type':'GET',
'success':function(response)
{
if(response==1)
{
$.ajax({
'url':'/analytics_1/LogButton',
'type':'POST',
'data':'userName='+un+'&buttonId=VIKALPLoginButton&pageTitle='+pageTitle,
'success':function()
{
window.open("index.html","_self");
}
});
}
else
{
alert("Invalid Credentials");
}
}
});
}
I create the Session in LogButton.java after checking if it's new
if(session.isNew())
{
System.out.println("session is not set, lets create the name");
associate=req.getParameter("userName");
session.setAttribute("Associate",associate);
}
else
{
System.out.println("session is already set, lets get the name");
associate=(String)session.getAttribute("Associate");
}
I get their name from the session I created after successful login
And I do some actions and logout,
$('#logout').on('click',function()
{
var pageTitle=$(document).attr('title');
$.ajax({
'url':'/analytics_1/LogButton',
'data':'buttonId=VIKALPLogoutButton&pageTitle='+pageTitle,
'type':'POST',
'success':function()
{
window.open('Login.html',"_self");
},
'error':function(err)
{
alert("haha:"+err.response);
}
});
});
In LogButton.java, I check if button is VIKALPLogoutButton, if true, i proceed to invalidate the session and remove Attribute
if(button.equals("VIKALPLogoutButton"))
{
System.out.println("deleting the session cuz of logout");
session.removeAttribute("Associate");
session.invalidate();
//System.out.println("what happens to the session? " +session.isNew());
}
All these happen as per required. Now comes the security use case : What should happen if I go to index.html without logging in?
So I started checking if session is set or not when index.html loads,
$(document).ready(function () {
$.ajax({
'url':'/analytics_1/GetAssocId',
'type':'POST',
'success':function(response)
{
if(response!="null")
{}
else
{
window.open("Login.html","_self");
}
$('#name').text(response);
}
});
.....
.....
}
GetAssocId.java:
public void doPost(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException
{
HttpSession session=req.getSession();
PrintWriter out=res.getWriter();
out.print(session.getAttribute("Associate"));
}
This also works fine, i.e it redirects me to Login.html if the session isn't created.
Now the thing is, I cannot Login, even after providing valid credentials, somehow the "Associate" attribute is set to null,
Below is the System.out.println output that I get in cmd
Above white line: Login,Logout action (notice the session invalidate output that I've given)
Below white line: Go directly to index.html, it redirects to Login.html, and you Login with your valid credentials,
Now this is my problem, It invalidates the session, yet still it says session is already existing . Even more confusing is, session is existing, but the value is null.
How do I overcome this problem? Please help
P.S:Other than the snippets I've provided for LogButton.java are not significant for this problem
HttpSession session=req.getSession();
If you look at the docs of getSession method
Returns the current HttpSession associated with this request or, if there is no current session and create is true, returns a new session.
If create is false and the request has no valid HttpSession, this method returns null.
You are calling req.getSession() method which gives you a new session. Probably to get the existing session you need to use
HttpSession session=req.getSession(false);
As you already invalidate the session, this gives you session as null .
Your other question
Now this is my problem, It invalidates the session, yet still it says session is already existing . Even more confusing is, session is existing, but the value is null.
It's because you created a new session, there are no attributes in it and that is the reason you getting null

GWT Getting username from url only works after refresh

My login based application, requires to always know the username of the logged in user. (MVP) . So I'm getting the username from the url, but when the page opens after the login succeeded, I can't get the username from the url, because it does not appear to exists, but it is there. It only works after a refresh. Then I'm able to get the username.
The URL is in the form http://127.0.0.1:8888/AdministrareBloc.html#AdminPlace:admin, where I'm splitting the String to only get the admin part.
I thought this is because it downloads the code before verifying the user. So I placed a split point in my code like this: (I don't know if I placed it correctly)
loginButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
final String username = usernameBox.getText();
final String password = passwordBox.getText();
GWT.runAsync(new RunAsyncCallback() {
#Override
public void onSuccess() {
performUserConnection(username, password);
}
#Override
public void onFailure(Throwable reason) {
// TODO Auto-generated method stub
}
});
}
});
private static void performUserConnection(String username, String password) {
DBConnectionAsync rpcService = (DBConnectionAsync) GWT.create(DBConnection.class);
ServiceDefTarget target = (ServiceDefTarget) rpcService;
String moduleRelativeURL = GWT.getModuleBaseURL() + "DBConnectionImpl";
target.setServiceEntryPoint(moduleRelativeURL);
rpcService.authenticateUser(username, password, new AsyncCallback<User>() {
#Override
public void onSuccess(User user) {
if (user.getType().equals("User")) {
String username = user.getUsername();
presenter.goTo(new UserPlace(username));
} else if (user.getType().equals("Admin")) {
String username = user.getUsername();
presenter.goTo(new AdminPlace(username));
}
}
}
}
This is happening when the user clicks the login button. Is the split point placed correclty, or not ? How can I get the username without needing to refresh the page after a successful login ?
UPDATE
I've tried a trick today, placing a Window.Location.reload() inside the AdminViewImpl and UserViewImpl, and when the application starts, then the page reloads every second, so this means for me that the split point is not correclty used and the browser downloads the code before he actually needs it, and that's why I'm able to see the username after the refresh, because it redownloads the code, and I'm already logged in when I refresh.
Thanks in advance

Adding attributes to Wicket session

There is an implementation of WebSession, which supposed to store ID of logged user:
public class SecurityWebSession extends AuthenticatedWebSession {
public SecurityWebSession(Request request) {
super(request);
bind();
}
...
#Override
public boolean authenticate(String username, String password) {
user = usersFacadeLocal.findByEmail(username);
if (user != null) {
try {
boolean valid = PasswordHash.validatePassword(password, user.getPassword());
if (valid) {
WebSession.get().setAttribute(USER_ID, user.getId());
}
return valid;
} catch (Exception ex) {
logger.error("Authenticate ERROR", ex);
}
}
return false;
}
}
However, when I access SecurityWebSession to get ID of logged user from WebPage class, it returns null. I came across that Session does not store values which were added from its body. But it perfectly stores values if set them from classes inherited from Wicket's WebPage.
I did not find any mention in documentation about this situation. How can I add to Session attributes from Session?
Do you use Wicket 6.19.0 by chance?
If this is the case then you hit https://issues.apache.org/jira/browse/WICKET-5845. It is fixed in 6.20.0.
If this is not the case then please create a new ticket with a quickstart application showing the problem. Thanks!
I guess the problem lies within AuthenticatedWebSession.signIn(final String username, final String password).
This one calls your authenticate method and will destroy() and bind() your session again (this is done to avoid Session fixation).
You can however temporarily store the values you need by overriding replaceSession():
// this will be called *after* a successful authenticate
#Override
public void replaceSession() {
//temp store any values you want to carry over to the new session...
super.replaceSession();
//reset them to the session after super.replaceSession();
}

How to keep flash when redirecting to the login page

I'm implementing an email mechanism in Play:
User gets an email with a validation link
Clicks on it, gets to a controller that saves the "validated" bit on the user model, then redirects him to another page.
Before redirecting, that last page puts a message into the flash object ... to be displayed later in whatever page the user ends up at, via javascript. The message says "thanks for validating your email".
The target page has #With(Secure.class), so if the user is not authenticated I reach the Secure.login() method.
Now, at this point, I find that flash does not contain the message I just put in there before the redirection. What is the correct way to use flash in a way that survives this redirect?
This seems to work:
public class OurSecure extends Controller {
#Before(unless={"login", "authenticate", "logout"})
static void checkAccess() throws Throwable {
// Authent
if(!session.contains("username")) {
// __ my modification __ :
flash.keep();
flash.put("url", "GET".equals(request.method) ? request.url : "/");
// seems a good default
login();
}
...
}
hmm... well, its a slightly different use case, but thats the way how I remember which page the user wanted to access when he got redirected to the login page, so I can redirect him back there after successful authentication. maybe it helps
#Before(only = "authenticate")
public static void preserveUrl()
{
String url = request.params.get("url");
if(
"authenticate".equals(request.actionMethod) &&
url != null &&
!url.toLowerCase().contains("http") &&
!url.toLowerCase().contains("ftp")
)
{
flash.put("url", url);
}
}
static boolean authenticate(String username, String password) {
if(username == null || password == null)
return false;
String passwordHash = Codec.hexMD5(password.trim());
Member m = Member.findByEmailAddressPasswordHashAndStatus(username, passwordHash, Member.STATUS.ACTIVE);
return m != null;
}

page after login in playframework

In my play! app,I have coded the controllers.Security as
class Security extends controllers.Secure.Security {
...
static void onDisconnected() {
Application.index();
}
static void onAuthenticated() {
User user = User.find("byEmail",Security.connected()).first();
if(user.isAdmin()) {
Admin.index();
}else {
System.out.println("onAuthenticated()::user not admin");
}
}
I have set the routes as
GET /admin/? Admin.index
* /admin module:crud
GET / Application.index
When I am on a page say pageX and click on the login link,the login form appears and I am able to login.If I login as admin ,it takes me to the Admin.index() and thereby to Admin/index.html view.So far so good
But,when I am on pageX,and click on login link,I expect to come back to pageX.Instead ,the Application.index() method is called and I am taken to the Application.index.html..
Is this the expected behaviour?
What do I have to do to get to pageX after login?
update:
I tried storing the url in flash using the #Before in Security controller
class Security extends controllers.Secure.Security {
#Before
static void storeCurrentUrl() {
System.out.println("storeCurrentUrl()");
flash.put("url", "GET".equals(request.method) ? request.url : "/");
}
static boolean authenticate(String username, String password) {
...
}
static void onAuthenticated() {
...
String url = flash.get("url");
System.out.println("url="+url);
if(!user.isAdmin()) {
if(url!=null) {
System.out.println("url not null");
redirect(url);
}else {
System.out.println("url null ..go to /");
redirect("/");
}
}
}
When I login,I get these terminal output
url=null
url null ..go to /
index()
I have put the login/logout links in main.html template which is inherited by all other pages
<div id="main">
<div class="auth">
Go to Admin Area<br/><br/>
Login<br/><br/>
Log out
</div>
In you controller, before calling 'login()' put the 'url' into flash something like:
flash.put("url", "GET".equals(request.method) ? request.url : "/");
Once successfully logged in, get the 'url' and redirect.
String url = flash.get("url");
redirect(url); //you may redirect to "/" if url is null
This will be the expected behaviour as this is the way your routing is setup. Click on login and get redirected to Application.index or Admin.index if admin user.
If you want to retrieve the page which you clicked the login link from you could add the current action to the login link and once authenticated redirect to this action.
ie. login link: GET /login?action=Application.something --> takes you to login page
then save action as a hidden field in your login form. When you authenticate the user render the action.
Play already do redirection to original url when you try to access a protected page while not logged in.
If you want to reuse this, you ca put your url in flash scope in the "onAuthenticated" method. In the source code, play call "redirectToOriginalURL" just after that based on the value of the "url" value.
static void onAuthenticated() {
flash.put("url", "GET".equals(request.method) ? request.url : "/");
}

Categories