Vaadin close UI of same user in another browser/tab/system - session

I'm doing a project in Vaadin 7. In that I need to implement something like below for the login.
A user 'A' is logged in to a system '1'. And again he logs into another system '2'. Now I want to know how to close the UI on the system '1'.
I tried something and can able to close the UI, If it is the same browser. But, for different systems/browser. I don't have any idea.
My Code:
private void closeUI(String attribute) {
for (UI ui : getSession().getUIs()) {
if(ui.getSession().getAttribute(attribute) != null)
if(ui.getSession().getAttribute(attribute).equals(attribute))
ui.close();
}
}
Can anyone help me in this?

I have a situation similar to your where I need to display several info regarding all sessions. What I did was I created my own Servlet extending the VaadinServlet with a static ConcurrentHashmap to save my sessions info, and a SessionDestroyListener to remove any info from the map upon logout. Initially I also had a SessionInitListener where I added the info in the hashmap but I realized I only had the user information after authentication so I moved this part to the page handling the login.
I guess you could do something similar, or at least this should get you started:
public class SessionInfoServlet extends VaadinServlet {
private static final ConcurrentHashMap<User, VaadinSession> userSessionInfo = new ConcurrentHashMap<>();
// this could be called after login to save the session info
public static void saveUserSessionInfo(User user, VaadinSession session) {
VaadinSession oldSession = userSessionInfo.get(user);
if(oldSession != null){
// close the old session
oldSession.close();
}
userSessionInfo.put(user, session);
}
public static Map<User, VaadinSession> getUserSessionInfos() {
// access the cache if we need to, otherwise useless and removable
return userSessionInfo;
}
#Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
// register our session destroy listener
SessionLifecycleListener sessionLifecycleListener = new SessionLifecycleListener();
getService().addSessionDestroyListener(sessionLifecycleListener);
}
private class SessionLifecycleListener implements SessionDestroyListener {
#Override
public void sessionDestroy(SessionDestroyEvent event) {
// remove saved session from cache, for the user that was stored in it
userSessionInfo.remove(event.getSession().getAttribute("user"));
}
}
}

Related

How to persist policy authorization results for users in ASP.NET Core, MVC 6?

Currently I have a simple custom policy handler that looks like so:
protected override void Handle(AuthorizationContext context, UserPolicyRequirement requirement)
{
// authorize user against policy requirements
if (_authorizationTask.AuthorizeUserAgainstPolicy(context.User, requirement))
{
// User passed policy req's
context.Succeed(requirement);
}
}
Problem is, this authorization step takes a long time to execute, but this is required in many different areas of the website. Is there any readily available mechanisms to save/cache the results of this policy authorization so that I only need to do this once per session?
I am currently using Windows Authentication, if that helps.
If per session way does not cause any problem, you can use Session to store user data. Simple implementation is something like below:
First you need a service to get user data from any store
public interface IGetUserDataService
{
<type> GetUserData();
}
I assume that there is Session configuration(see) and IGetUserDataService implementation.
Then you need to create a middleware to handle Session
public class SessionMiddleware
{
private readonly RequestDelegate _next;
private readonly IGetUserDataService _getUserDataService;
public SessionMiddleware(RequestDelegate next, IGetUserDataService getUserDataService)
{
_next = next;
_getUserDataService = getUserDataService;
}
public async Task Invoke(HttpContext context)
{
//user data is obtained only once then is stored in Session
if (context.Session.Get("UserData") == null)
{
context.Session.Set("UserData", getUserDataService.GetData());
}
await _next.Invoke(context);
}
}
//In Startup.cs
app.UseMiddleware<SessionMiddleware>();
Finally get and use session data in handler
public class YourHandler : AuthorizationHandler<YourRequirement>
{
private readonly IHttpContextAccessor _accessor;
public YourHandler(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
protected override void Handle(AuthorizationContext context, PermissionRequirement requirement)
{
var userData =(<type>)_accessor.HttpContext.Session.Get("UserData");
// check
}
}

Disconnect client session from Spring websocket stomp server

I've searched quite a bit and been unable to find this: Is there a way that a spring websocket stomp server can disconnect a client based on the sessionId (or really based on anything at all)?
It seems to me that once a client connects to a server there is nothing that allows the server to disconnect the client.
Actually using some workarounds you can achieve what you want.
For that you should do:
Use java configuration (not sure if it is possible with XML config)
Extend your config class from WebSocketMessageBrokerConfigurationSupport and implement WebSocketMessageBrokerConfigurer interface
Create custom sub-protocol websocket handler and extend it from SubProtocolWebSocketHandler class
In your custom sub-protocol websocket handler override afterConnectionEstablished method and you will have access to WebSocketSession :)
I've created sample spring-boot project to show how we can disconnect client session from server side:
https://github.com/isaranchuk/spring-websocket-disconnect
You can also disconnect session by implementing a custom WebSocketHandlerDecorator:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig<S extends ExpiringSession> extends AbstractSessionWebSocketMessageBrokerConfigurer<S> {
#Override
public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
#Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
#Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
session.close(CloseStatus.NOT_ACCEPTABLE);
super.afterConnectionEstablished(session);
}
};
}
});
super.configureWebSocketTransport(registration);
}
#Override
protected void configureStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/home")
.setHandshakeHandler(new DefaultHandshakeHandler(
new UndertowRequestUpgradeStrategy() // If you use undertow
// new JettyRequestUpgradeStrategy()
// new TomcatRequestUpgradeStrategy()
))
.withSockJS();
}
}
As far as I know the API doesn't provide what you are looking for, on server-side you can only detect disconnect events. If you want to disconnect a certain client I think you must go for a litte workaround, e.g. this one:
Write a client-side javascript function that is able to trigger a disconnect
As soon as your client is connected to the server, generate a client ID in your javascript and send it to the server. Remember the ID on the client, you'll need it in step (4).
At the time you want the server to disconnect the connection to the specific client (identified by the ID), send a message containing the ID back to the client.
Now your client javascript evaluates the message send from the server and decides to call the disconnect function you wrote in step (1).
Your client disconnects itself.
The workaround is a bit cumbersome but it'll work.
I relied on the idea of #Dániel Kis and implemented the websocket session management with the key point of storing websocket sessions for authenticated users in Singleton-like object.
// WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
#Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
#Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
// We will store current user's session into WebsocketSessionHolder after connection is established
String username = session.getPrincipal().getName();
WebsocketSessionHolder.addSession(username, session);
super.afterConnectionEstablished(session);
}
};
}
});
}
}
Class to store websocket users' sessions WebsocketSessionHolder. I use 'synchronized' blocks for thread safety. Actually this blocks are not expensive operations because each of methods (addSession and closeSessions) are used not so often (On establishing and terminating connection). No need to use ConcurrentHashMap or SynchronizedMap here because we perform bunch of operations with the list in these methods.
// WebsocketSessionHolder.java
public class WebsocketSessionHolder {
static {
sessions = new HashMap<>();
}
// key - username, value - List of user's sessions
private static Map<String, List<WebSocketSession>> sessions;
public static void addSession(String username, WebSocketSession session)
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions == null)
userSessions = new ArrayList<WebSocketSession>();
userSessions.add(session);
sessions.put(username, userSessions);
}
}
public static void closeSessions(String username) throws IOException
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions != null)
{
for(var session : userSessions) {
// I use POLICY_VIOLATION to indicate reason of disconnecting for a client
session.close(CloseStatus.POLICY_VIOLATION);
}
sessions.remove(username);
}
}
}
}
And the final touch - terminating (disconnecting) specified user websocket sessions ("ADMIN" in the example), say in some Controller
//PageController.java
#Controller
public class PageController {
#GetMapping("/kill-sessions")
public void killSessions() throws Exception {
WebsocketSessionHolder.closeSessions("ADMIN");
}
}
In case of xml configuration you can use <websocket:decorator-factories> in the <websocket:transport> of your <websocket:message-broker>.
Create custom WebSocketHandlerDecorator and WebSocketHandlerDecoratorFactory which implement decorate method.
This may seem brief but I am not certain what the implementation would look like in your case. But, I think there are some circumstances that would warrant this workaround/solution:
Set a timeout on the back-end (say 30 seconds):
This is how you would do it with Spring Boot Websocket (and Tomcat):
#Bean
public ServletServerContainerFactoryBean websocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxSessionIdleTimeout(MAX_SESSION_IDLE_TIMEOUT);
return container;
}
If you want to keep the session open - continue to send messages or else actively send ping/pongs. In the case that you want the session to disconnect, stop the ping/pong interaction somewhere suitable in you application.
Of course, if you are wanting to disconnect immediately, this doesn't seem to be an appropriate solution. But if you are simply trying to reduce the number of active connections, ping/pong may be a good fit since it keeps a session open only so long as messages are actively being sent, preventing the session from being closed prematurely.
first you have to introduce a class as your User class by inheritance then use it like this:
if (userObject instanceof User) {
User user = (User) userObject;
if (user.getId().equals(userDTO.getId())) {
for (SessionInformation information : sessionRegistry.getAllSessions(user, true)) {
information.expireNow();
}
}
}

How do I safely detect if Session Scope exists in a service?

I have service that is called both from Quartz (w/o a session scope), and interactively from a Web Flow (w/ a session scope).
When called from the Web Flow, there may be some optional flags set and I would like to safely check for them, IF THEY EXIST.
I'm using session scope because the functions I'm calling are far down a call chain, and passing the options, or scope all the way down will touch a lot of code.
I'm wondering if there is something like:
if(someObject.session?.myFlag)
where "session" refers to the session scope if called from a web flow, or null if called from Quartz.
Thanks in advance!
As you seem to already know, accessing the session scope from a service is not something to be encouraged, because the HTTP session should only be used within the web layer (GSPs, controllers, filters, etc.).
Now you didn't hear this from me, but you can access the current session from anywhere like this:
def session = org.codehaus.groovy.grails.web.util.WebUtils.
retrieveGrailsWebRequest().session
Once you have access to the session you can check if attributes exist or retrieve them using the usual HttpSession API.
I would go with a Filter and ThreadLocal approach.
Create a class with a static ThreadLocal variable which holds a reference to an instance of the class. This instance can then be referenced from anywhere from the executing thread and it will provide access to your variables and flags. This way you are not directly referencing to HTTP session API in your service.
Finally create a Filter in which you set up the ThreadLocal value before executing the rest of the chain. Remember to clear the state of the value after the thread is complete.
class MyExecutionContext {
private static ThreadLocal instance = new ThreadLocal<MyExecutionContext>()
private HttpSession session
private ServletRequest request
// set the state for current thread
// you can add request here too, if you want/need
public static void setContext(ServletRequest req, HttpSession s) {
stateInstance.set(new MyExecutionContext(req, s))
}
// get the state of current thread
public static getContext() {
return instance.get()
}
// clear the current state
public static void clearContext() {
stateInstance.remove()
}
// private constructor
private MyExecutionContext(ServletRequest req, HttpSession s) {
request = req
session = s
}
// now the actual methods to query any kinds of things you need
// from session (or request if you gave it in the constructor)
public String getSomething() {
(String) session?.getAttribute("somethingInSession")
}
public String getSomethingElse() {
(String) request?.getAttribute("somethingInRequest")
}
}
class ContextFilter extends Filter {
public void doFilter(...) {
try {
MyExecutionContext.setContext(request, request.getSession(false))
chain.doFilter(req, res)
} finally {
// make sure you clear the state
MyExecutionContext.clearContext()
}
}
}
// usage in your service
class YourService {
def method() {
if (MyExecutionContext?.context?.something) {
// value exists in session
}
}
}

Accessing ServletContext object in Action class in Struts 1.2

I have been given a use-case, to come up with a solution to allow configured number of users per user id to be logged in to my application at any given time.
For example : userid 'parentuser' can be used to log in to the application for a max of 10 times at any time.After this limit, the user will not allowed to log in as max number of users are accessing the application for that user.
Now, To implement this, I have created a context listener which will instantiate an attribute which I'll keep updating as the user logs in the application in the Action class.
My Context Listener is as under :
public class ApplicationContextListener implements ServletContextListener {
private Map<String, List<ApplicationContextBean>> userMap;
#Override
public void contextDestroyed(ServletContextEvent arg0) {
userMap = null;
}
#Override
public void contextInitialized(ServletContextEvent event) {
userMap = new HashMap<String, List<ApplicationContextBean>>();
}
public Map<String, List<ApplicationContextBean>> getUserMap() {
return userMap;
}
public void setUserMap(Map<String, List<ApplicationContextBean>> userMap) {
this.userMap = userMap;
}
}
web.xml is as under
<listener>
<listener-class>com.pcs.bpems.portal.listener.ApplicationContextListener</listener-class>
</listener>
Question : How can I now access this context object 'userMap' from my action class? If anyone has any other approach different than this also, kindly post the same.
Thanks
The answer is in the title of your question: store the Map (or an object wrapping the map and providing useful methods) into an attribute of the servlet context (accessible from the event), and retrieve it from wherever you want: the HttpServletRequest provides access to the servlet context.
A better solution, which would also work in case your application is clustered, would be to use the database.
Also, don't forget to decrement the counter when the session expires.
This can be stored in the Servlet Context as under :
#Override
public void contextInitialized(ServletContextEvent event) {
userMap = new HashMap<String, Map<String,List<ApplicationContextBean>>>();
event.getServletContext().setAttribute(ApplicationConstants.LOGGED_IN_USERS, userMap);
}
The stored parameters can be then fetched from the HttpSession Object as under :
currentSession.getServletContext().getAttribute(LOGGED_IN_USERS)

How to run code on Application opens in Android?

My Android app need the user to create an account to be able to use the app. The account info is stored in SQLite database. When the application starts I check if the user has an account, if not I show a sign up activity for the user.
Now I get reports from users that they sometimes comes to the sign up activity even if they've already created an account. This happens when they've closed the application and reopen it again.
This is the code I'm using and I need to figure out what the problem might be:
//MyApplication.java
public class MyApplication extends Application {
private DataBaseUtility dbu;
public boolean hasAccount;
#Override
public void onCreate() {
super.onCreate();
//Init sqlite database
this.dbu = new DataBaseUtility(this);
//This loads the account data from the database and returns true if the user has already created an account
this.hasAccount = loadAccount();
}
public boolean loadAccount() {
boolean loadedData = false;
String query = "SELECT data FROM tblaccount WHERE tblaccount.deleted=0";
Cursor cursor = this.dbu.getCursor(query);
if (cursor != null) {
while (cursor.moveToNext()) {
loadedData = true;
}
cursor.close();
}
return loadedData;
}
}
//MainActivity.java
public class MainActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyApplication application = (MyApplication)getApplication();
if (!application.hasAccount) {
//Take the user to the sign up activity
}
}
My idea is that maybe sometimes MainActivity.onCreate() runs before MyApplication.onCreate(). Can that be the case?
In application's onCreate, you are checking if the user has an account and setting a boolean.
You are checking in the MainActivity's onCreate if the user has an account through the application's boolean.
application's onCreate() executing before MainActivity's onCreate() is always the case! It is impossible for a different execution path to occur and since application's onCreate() does not have a Runnable it is a 100% garantuee.
Please make sure you're DataBaseUtility does not have any Runnables.
Anyway STILL there are several ways to reproduce the error! I will not state these now but you can know them when you see:
SOLUTION
MainActivity You have forgotten to update application.hasAccount upon successfull sign up~
public class MainActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyApplication application = (MyApplication)getApplication();
if (!application.hasAccount) {
//Take the user to the sign up activity
//if(successful) application.hasAccount = true
}
}
To avoid database exceptions
I use this:
REMARK It would be much better to use more strong persistent status saving for the database -i.e. SharedPreferences
boolean isOpened = false;
//When I need to open
if(!isOpened){
//open
isOpened = true;
}
//When I need to close
if(isOpened){
//close
isOpened = false;
}
onDestroy() { //every onDestroy
if(isOpened){
//close
}
}

Resources