Skip to content

Commit

Permalink
refactoring the AnnisUser class to fix #434
Browse files Browse the repository at this point in the history
AnnisUser was not serializable. In case the session was written to the disk by the server AnnisUser could either have transient variables (like the Client) which are invalid after the object has been restored or you can re-create the client on request but then you need to store the password in the session disk storage as well. While creating the "Client" object on the fly and caching it is now implemented, the "password" field is still marked as "transient" to ensure it is not written to disk.

The actual new behavior is that the user is properly informed whenever the password was lost because it was written to disk and he/she is requested to login again instead of silently failing in this case.
  • Loading branch information
thomaskrause committed Sep 3, 2015
1 parent d1f14c2 commit ddf6861
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 46 deletions.
2 changes: 0 additions & 2 deletions annis-gui/src/main/java/annis/gui/LoginListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package annis.gui;

import com.sun.jersey.api.client.WebResource;

/**
*
* @author Thomas Krause <[email protected]>
Expand Down
51 changes: 51 additions & 0 deletions annis-gui/src/main/java/annis/gui/MainToolbar.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import static annis.libgui.AnnisBaseUI.USER_LOGIN_ERROR;
import annis.libgui.AnnisUser;
import annis.libgui.Helper;
import annis.libgui.LoginDataLostException;
import com.google.common.eventbus.Subscribe;
import com.vaadin.data.validator.EmailValidator;
import com.vaadin.server.DeploymentConfiguration;
import com.vaadin.server.ExternalResource;
Expand Down Expand Up @@ -313,6 +315,32 @@ public void buttonClick(Button.ClickEvent event)
updateSidebarState();
MainToolbar.this.updateUserInformation();
}

@Override
public void attach()
{
super.attach();

UI ui = UI.getCurrent();
if(ui instanceof AnnisBaseUI)
{
((AnnisBaseUI) ui).getLoginDataLostBus().register(this);
}
}

@Override
public void detach()
{
UI ui = UI.getCurrent();
if(ui instanceof AnnisBaseUI)
{
((AnnisBaseUI) ui).getLoginDataLostBus().unregister(this);
}

super.detach();
}





Expand Down Expand Up @@ -579,5 +607,28 @@ public void call(JSONArray arguments) throws JSONException

}
}

@Subscribe
public void handleLoginDataLostException(LoginDataLostException ex)
{

Notification.show("Login data was lost, please login again.",
"Due to a server misconfiguration the login-data was lost. Please contact the adminstrator of this ANNIS instance.",
Notification.Type.WARNING_MESSAGE);

for (LoginListener l : loginListeners)
{
try
{
l.onLogout();
}
catch (Exception loginEx)
{
log.error("exception thrown while notifying login listeners", loginEx);
}
}
updateUserInformation();

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import annis.libgui.AnnisBaseUI;
import annis.libgui.AnnisUser;
import annis.libgui.Helper;
import annis.libgui.LoginDataLostException;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import com.google.common.io.Resources;
Expand Down Expand Up @@ -145,16 +146,15 @@ private void doPost(VaadinSession session, VaadinRequest request,

String webserviceURL = (String) annisServiceURLObject;

Client client = Helper.createRESTClient(username, password);

try
{
WebResource res = client.resource(webserviceURL)
AnnisUser user = new AnnisUser(username, password);
WebResource res = user.getClient().resource(webserviceURL)
.path("admin").path("is-authenticated");
if ("true".equalsIgnoreCase(res.get(String.class)))
{
// everything ok, save this user configuration for re-use
Helper.setUser(new AnnisUser(username, client));
Helper.setUser(user);
}
}
catch (ClientHandlerException ex)
Expand All @@ -163,6 +163,12 @@ private void doPost(VaadinSession session, VaadinRequest request,
"Authentification error: " + ex.getMessage());
response.setStatus(502); // bad gateway
}
catch (LoginDataLostException ex)
{
session.getSession().setAttribute(AnnisBaseUI.USER_LOGIN_ERROR,
"Lost password in memory. Sorry.");
response.setStatus(500); // server error
}
catch (UniformInterfaceException ex)
{
if (ex.getResponse().getStatus() == Response.Status.UNAUTHORIZED.
Expand Down
27 changes: 15 additions & 12 deletions annis-libgui/src/main/java/annis/libgui/AnnisBaseUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import com.google.common.base.Charsets;
import com.google.common.eventbus.EventBus;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.sun.jersey.api.client.Client;
import com.vaadin.annotations.Theme;
import com.vaadin.sass.internal.ScssStylesheet;
import com.vaadin.server.ClassResource;
Expand All @@ -36,9 +36,6 @@
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.UI;
import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
Expand Down Expand Up @@ -102,6 +99,8 @@ public class AnnisBaseUI extends UI implements PluginSystem, Serializable

private TreeSet<String> alreadyAddedCSS = new TreeSet<String>();

private final EventBus loginDataLostBus = new EventBus();

@Override
protected void init(VaadinRequest request)
{
Expand All @@ -112,9 +111,9 @@ protected void init(VaadinRequest request)

// store the webservice URL property explicitly in the session in order to
// access it from the "external" servlets
getSession().getSession().setAttribute(WEBSERVICEURL_KEY,
getSession().getAttribute(Helper.KEY_WEB_SERVICE_URL));
getSession().getSession().setAttribute(WEBSERVICEURL_KEY,
getSession().getAttribute(Helper.KEY_WEB_SERVICE_URL));

getSession().setAttribute(CONTEXT_PATH, request.getContextPath());
alreadyAddedCSS.clear();

Expand Down Expand Up @@ -384,9 +383,7 @@ private void checkIfRemoteLoggedIn(VaadinRequest request)
String remoteUser = request.getRemoteUser();
if(remoteUser != null)
{
// treat as anonymous user
Client client = Helper.createRESTClient();;
Helper.setUser(new AnnisUser(remoteUser, client, true));
Helper.setUser(new AnnisUser(remoteUser, null, true));
}
}

Expand Down Expand Up @@ -503,7 +500,13 @@ public boolean handleRequest(VaadinSession session, VaadinRequest request,
checkIfRemoteLoggedIn(request);
// we never write any information in this handler
return false;
}

}
}

public EventBus getLoginDataLostBus()
{
return loginDataLostBus;
}


}
55 changes: 30 additions & 25 deletions annis-libgui/src/main/java/annis/libgui/AnnisUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,29 @@
package annis.libgui;

import com.sun.jersey.api.client.Client;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicInteger;

public class AnnisUser
public class AnnisUser implements Serializable
{
private transient Client client;
private String userName = "";
private boolean remote = false;


public AnnisUser(String userName, Client client)
private final String userName;
/** Never store the password on the disk */
private final transient String password;
private final boolean remote;

public AnnisUser(String userName, String password)
{
this.userName = userName;
this.client = client;
this.password = password;
this.remote = false;
}

public AnnisUser(String userName, Client client, boolean remote)
public AnnisUser(String userName, String password, boolean remote)
{
this.userName = userName;
this.client = client;
this.password = password;
this.remote = remote;
}

Expand All @@ -43,20 +48,28 @@ public String getUserName()
return userName;
}

public void setUserName(String userName)
{
this.userName = userName;
}

public Client getClient()
public Client getClient() throws LoginDataLostException
{
if(client == null)
{
if(remote == true)
{
// treat as anonymous user
client = Helper.createRESTClient();
}
else
{
if(password == null)
{
throw new LoginDataLostException();
}
client = Helper.createRESTClient(userName, password);
}
}
return client;
}

public void setClient(Client client)
{
this.client = client;
}

/**
* True if the user a remote user, thus cannot e.g. logout by itself
Expand All @@ -66,12 +79,4 @@ public boolean isRemote()
{
return remote;
}

public void setRemote(boolean remote)
{
this.remote = remote;
}



}
31 changes: 28 additions & 3 deletions annis-libgui/src/main/java/annis/libgui/Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.uri.UriComponent;
import com.sun.jersey.client.apache4.ApacheHttpClient4;
import com.sun.jersey.client.apache4.config.ApacheHttpClient4Config;
import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config;
Expand Down Expand Up @@ -208,7 +207,20 @@ public static WebResource getAnnisWebResource(String uri, AnnisUser user)

if (user != null)
{
return user.getClient().resource(uri);
try
{
return user.getClient().resource(uri);
}
catch (LoginDataLostException ex)
{
log.error("Could not restore the login-data from session, user will invalidated", ex);
setUser(null);
UI ui = UI.getCurrent();
if(ui instanceof AnnisBaseUI)
{
((AnnisBaseUI) ui).getLoginDataLostBus().post(ex);
}
}
}

// use the anonymous client
Expand All @@ -234,7 +246,20 @@ public static AsyncWebResource getAnnisAsyncWebResource(String uri,

if (user != null)
{
return user.getClient().asyncResource(uri);
try
{
return user.getClient().asyncResource(uri);
}
catch (LoginDataLostException ex)
{
log.error("Could not restore the login-data from session, user will invalidated", ex);
setUser(null);
UI ui = UI.getCurrent();
if(ui instanceof AnnisBaseUI)
{
((AnnisBaseUI) ui).getLoginDataLostBus().post(ex);
}
}
}

// use the anonymous client
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2015 Corpuslinguistic working group Humboldt University Berlin.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package annis.libgui;

/**
* This indicates the login-data is not available any longer.
*
* If this exception was thrown the user interface should show
* to the user that he/she is effectivly logged out.
* @author Thomas Krause <[email protected]>
*/
public class LoginDataLostException extends Exception
{

}

0 comments on commit ddf6861

Please sign in to comment.