Wicket Session with more than one user logged in - java

I am building my first Java Application with Wicket and have a bit of a problem with Wicket Sessions.
My Problem: When a second User logs into the application he overrides the session for the first user -> both are working on the second session now. Although both Users create a new Session when logging in.
My Code:
WicketSession.java:
public class WicketSession extends WebSession {
private UserBean currentUser;
public WicketSession(Request request) {
super(request);
}
public static WicketSession get() {
return (WicketSession) Session.get();
}
// getter/setter
in my Application class:
#Override
public Session newSession(Request request, Response response) {
return new WicketSession(request);
}
and the login (short version w/o ifs, to make it readable):
#Override
public final void onSubmit() {
if (signIn(wiaUsername, wiaPassword)) {
getSession().bind();
setResponsePage(new CharListDetail());
} else {
error("Unknown username/ password");
}
}
private boolean signIn(String username, String password) {
currentUser = UserProxy.getInstance().getElementByUser(username, password);
WicketSession.get().setCurrentUser(currentUser);
return true;
}
This all works fine for one user. But the moment a second user logs in
WicketSession.get().setCurrentUser(currentUser);
sets the current User to the new User and both logged in Users are the same. How do I prevent this problem?

After lots of searching the net I found the solution.
The problem was that I saved the currentUser as a UserBean and not as a String. I dont know exactly why it doesn't work in Wicket to store the User as a Bean, but now finally it's working.

Related

How do I look up an HttpSession by it's Id in a Springboot based application?

I want to obtain a HttpSession object by URL Path variable id to get some attributes from it.
Context:
I'm trying to implement a web server that has a register and login sub-systems as a learning exercise.
I'm using JAVA, Springboot and various other spring dependencies like hibernate, jdbc, etc.
I got the behavior I wanted, but as I tested my logic with an Android client application I encountered that the register confirmation link I send, does not work if I access it from another device, because the device-sender has a different session and thus my logic fails.
The flow of my registration is as follows:
User POSTs at /register -> { name, email, password }
Server saves this information in their session and sends confirmation email with /register/confirm/{token}
As the user GETs at /register/confirm/{token} that was send to their email,
the server checks if this token is contained in their session and commits the information from the session to the database.
Of course if I register from the device and try to confirm through another device they'd have different sessions and hence the temp information would not be available to the other device, but this is the same user trying to register and I'm looking for a work around. The way I decided to change my code is to send the user /register/confirm/{sessionId}+{token} to their email, but I can't find my way around obtaining the other HttpSession.
(#ServletComponentScan)
I tried to create a HttpSessionListener and tried to maintain a HashMap of HttpSession's but for some reason the Framework would instantiate the Listener object, but never send createSession events to it thus it's HashMap is always empty, thus {sessionId} is never found.
To provide some extra code for context.
My Listener:
#WebListener
public class SessionLookUpTable implements HttpSessionListener {
static final HashMap<String, HttpSession> sessionHashMap = new HashMap<>();
public SessionLookUpTable() {
super();
System.out.println("-------------- Session Listener Created"); // DEBUG
}
// Always empty for some reason, despite constructor being called
static public Optional<HttpSession> findSessionById(String sessionId) {
if (!sessionHashMap.containsKey(sessionId))
return Optional.empty();
return Optional.of( sessionHashMap.get( sessionId ) );
}
#Override
public void sessionCreated(HttpSessionEvent se) {
HttpSessionListener.super.sessionCreated(se);
HttpSession session = se.getSession();
sessionHashMap.put( session.getId(), session );
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSessionListener.super.sessionDestroyed(se);
sessionHashMap.remove(se.getSession().getId() );
}
};
The controller entry points
#PostMapping("/register")
public String register(HttpSession session,
#RequestParam("email") String username,
#RequestParam("password") String password,
#RequestParam("password2") String pw2)
{
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setPrivilegeLevel( Role.USER_PRIVILEGE_NORMAL );
if(session.getAttribute(ATTRIBUTE_USER_ID) != null) {
return "Already registered";
}
if(!userService.isUserDataValid(user)) {
return "Invalid input for registry";
}
if(userService.usernameExists(user.getUsername())) {
return "User already exists";
}
session.setAttribute(ATTRIBUTE_REGISTER_DATA, user);
String token = userService.sendConfirmationEmail( session );
if(token != null) {
session.setAttribute(ATTRIBUTE_USER_ID, 0L );
session.setAttribute(ATTRIBUTE_REGISTER_TOKEN, token);
}
return "A link was sent to your email.";
}
#RequestMapping("/register/confirm/{sessionId}+{token}")
void confirmRegister(HttpSession sessionIn,
#PathVariable("sessionId") String sessionId,
#PathVariable("token") String token) {
Optional<HttpSession> optSession = SessionLookUpTable.findSessionById( sessionId );
if(optSession.isEmpty())
return;
HttpSession session = optSession.get();
// Multiple confirmations guard
Long userId = (Long)session.getAttribute(ATTRIBUTE_USER_ID);
if( userId != null && userId != 0L ){
return;
}
String sessionToken = (String)session.getAttribute(ATTRIBUTE_REGISTER_TOKEN);
if(!sessionToken.equals(token)) {
return;
}
User user = (User)session.getAttribute(ATTRIBUTE_REGISTER_DATA);
user.setDateRegistered( LocalDate.now() );
Long id = userService.register( user );
session.setAttribute(ATTRIBUTE_USER_ID, id);
}
I'm stuck at this stage for quite a while, so any help is appreciated. Thank you.

How to access the logged in principal from HttpSessionListener with Java EE Security?

I have an application with #CustomFormAuthenticationMechanismDefinition, and I would like to log the username, session id, IP address, etc. both at login and at logout. The HttpAuthMechanism that gets applied with this annotation associate the given session with the principal, which I can access through the SecurityContext. With a direct logout, I have no problem logging, but I would also like to log when session times out. So I created a HttpSessionListener and in its sessionDestroyed() method I try to access the logged in user through SecurityContext, but it returns an empty set, maybe because the securityContext got invalidated already.
One solution I have in my mind is to store the user principal in a session parameter (which likely happens with the HttpAuthMechanism implementation) and access it from there from the HttpSessionEvent object, but that doesn't feel like the cleanest solution. Is there another Listener I can use or some other solution?
I went with the custom HttpAuthenticationMechanism, here is it if anyone would need it (though I would be more than glad to have some feedback on whether or not it has any security flaws, or improvements).
In an #ApplicationScoped class implementing HttpAuthenticationMechanism:
#Override
public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {
if (!httpMessageContext.isProtected()) {
return httpMessageContext.doNothing();
}
HttpSession session = request.getSession(false);
Credential credential = httpMessageContext.getAuthParameters().getCredential();
// If we already have a session, we get the user from it, unless it's a new login
if (session != null && !(credential instanceof UsernamePasswordCredential)) {
User user = (User) session.getAttribute("user");
if (user != null) {
return httpMessageContext.notifyContainerAboutLogin(user, user.getRoles());
}
}
// If we either don't have a session or it has no user attribute, we redirect/forward to login page
if (!(credential instanceof UsernamePasswordCredential)) {
return redirect(request, response, httpMessageContext);
}
// Here we have a Credential, so we validate it with the registered IdentityStoreHandler (injected as idStoreHandler)
CredentialValidationResult validate = idStoreHandler.validate(credential);
Context context = new Context();
context.setIp(request.getRemoteAddr());
if (validate.getStatus() == CredentialValidationResult.Status.VALID) {
session = request.getSession(true);
CallerPrincipal callerPrincipal = validate.getCallerPrincipal();
session.setAttribute("user", callerPrincipal);
context.setUser(callerPrincipal);
context.setSessionId(session.getId());
Logger log = new Logger(logger, "validateRequest", context);
log.debug("Logged in user: " + callerPrincipal.getName());
String redirectPage = "whatYouWant.xhtml";
redirect(request, response, httpMessageContext, redirectPage);
return httpMessageContext.notifyContainerAboutLogin(validate);
} else if (validate.getStatus() == CredentialValidationResult.Status.NOT_VALIDATED) {
return redirect(request, response, httpMessageContext);
} else {
// Logging
return httpMessageContext.responseUnauthorized();
}
}
And in an implemented HttpSessionListener:
#Override
public void sessionDestroyed(HttpSessionEvent se) {
User user = (User) se.getSession().getAttribute("user");
if (user != null) {
// logging
}
}

Handling sessions and remembering logged in user with vertx

Currently when a user logs in to my web server using a web POST form, a custom authenticator and a custom user. I have the CustomUser put into the Session provided by the RoutingContext because, when using RoutingContext#setUser it only changes the user for that request and as soon as the user is redirected from the login processing page to their destination the CustomUser has been lost.
However, it also seems as though the Session in RoutingContext for the new page doesn't have any user stored in the entry where the auth placed the CustomUser, could this be sending a completely different Session?
Routing:
//ROUTE DEFINITIONS
// SESSION AND COOKIE
router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)).setNagHttps(false)); //TODO SSL
router.route().handler(CookieHandler.create());
// STATIC
router.route("/").handler(new StaticHandler()); //BASE
router.route("/admin").handler(new StaticHandler()); //ADMIN PAGE
// FORM REQUESTS
router.route("/login").handler(new AuthAndRegHandler(new CustomAuth(), dbController)); //LOGIN REQUEST
router.route("/logout").handler(new AuthAndRegHandler(new CustomAuth(), dbController)); //LOGOUT REQUEST
// AJAX
router.route("/ajax/updateInvoice").handler(new AjaxHandler());
// ERRORS
router.route().failureHandler(new ErrorHandler());
router.route().handler(handle -> {
handle.fail(404);
});
//END DEFINITIONS
AuthAndRegHandler:
public class AuthAndRegHandler extends AuthHandlerImpl {
private DatabaseController db;
private CustomAuth authProvider;
public AuthAndRegHandler(CustomAuth authProvider, DatabaseController db) {
super(authProvider);
this.db = db;
this.authProvider = authProvider;
}
#Override
public void handle(RoutingContext event) {
Logger log = LoggerFactory.getLogger(this.getClass());
HttpServerResponse response = event.response();
HttpServerRequest request = event.request();
Session session = event.session();
String requestedPath = request.path();
authProvider.setJdbc(db.getJdbc()); //returns a JDBCClient
if(requestedPath.equalsIgnoreCase("/login")) {
if(request.method() != HttpMethod.POST)
event.fail(500);
else {
request.setExpectMultipart(true);
request.endHandler(handle -> {
MultiMap formAtts = request.formAttributes();
String email = formAtts.get("email");
String pw = formAtts.get("password");
log.info(email + ":" + pw + " login attempt");
authProvider.authenticate(new JsonObject()
.put("username", email)
.put("password", pw), res -> {
if(res.succeeded()) {
CustomUser userToSet = (CustomUser) res.result();
session.put("user", userToSet);
log.info("Login successful for " + email);
response.putHeader("Location", "/").setStatusCode(302).end();
} else {
event.fail(500);
log.error("Auth error for " + request.host());
}
});
});
}
}
}
}
CustomAuth returns true every time for testing purposes.
StaticHandler
CustomUser user = session.get("user");
event.setUser(user);
response.putHeader("Content-Type", "text/html");
if(user != null) {
log.info(user.principal().getString("email") + " user detected");
event.setUser(user);
} else
log.info("Null user request detected"); //Constantly outputs, even after a login form has been submitted
I'm not entirely sure what's going wrong here. Vertx has sub-optimal documentation for a rookie like myself on session and handling things without their out-of-the-box implementations. Any help on how to log someone in and maintain their session like a normal website would be appreciated.
For those who stumble upon the same problem, but usually skip the comments:
Vert.x SessionHandler depends on CookieHandler, and the order is important here.
From the Vert.x examples:
router.route().handler(CookieHandler.create());
router.route().handler(sessionHandler);

How can I get the current logged in gmail user from cloud end point?

I am trying to get the current email id of the logged in google user. I tried something like the following which works in dev mode but not in production mode.
public class EndpointAPI {
#ApiMethod(httpMethod = HttpMethod.GET, path = "getuser")
public Container getLoggedInUser() {
UserService userService = UserServiceFactory.getUserService();
User guser = userService.getCurrentUser();
Container container = new Container();
container.user = "user not logged in";
if (null != guser)
container.user = guser.getEmail();
return container;
}
public class Container {
public String user;
}
}
I tried looking at the documentation (and tried adding client ids, scope etc) but could not successfully find what I need to do.
If someone can post a simple working example it will be much appreciated.
Regards,
Sathya
At simplest, you should register a client ID for a web application, and request a User object within the method signature of your API call. Example that supports requests from the JS client:
Ids.java:
public class Ids {
public static final String WEB_CLIENT_ID = "12345.apps.googleusercontent.com";
}
MyEndpoint.java:
#Api(clientIds = {Ids.WEB_CLIENT_ID})
public class MyEndpoint {
public getFoo(User user) throws OAuthRequestException {
if (user != null) {
// do something with user
} else {
throw new OAuthRequestException("Invalid user.");
}
}
}
user will automatically be populated with the current user represented by the token passed to your API, or null in the case of an invalid or missing token. The example above throws an exception when there isn't a valid user object, but you can also choose to allow unauthenticated access.
Check out the docs for more.

Returning on the form when the validation is completed and keeping the value on the input field

I am writing Web application and trying to integrate Spring Web MVC 3.0 framework. I want to validate input field from XHTML page. The form (what holds one input field) submitted, but then the page is redirected. If you explicitly redirect to the same form (registration.htm) the value entered in the input field disappears, what is not al right. I want the value stay in the input field.
This is my controller:
#Controller
public class UserNameController
{
#InitBinder()
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new UserNameValidator());
}
#RequestMapping(value="userName.htm",method=RequestMethod.POST)
public ModelAndView userName(#Valid #RequestParam("uName") String uName)
{ System.out.println("__________________________ "+ uName);
return new ModelAndView("registration");
}
public class UserNameValidator implements Validator
{
public boolean supports(Class<?> clazz)
{
return User.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors)
{
System.out.println("=======================");
User user = (User) target;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "uName", "field.required", "Required field");
if(!errors.hasFieldErrors("uName"))
{
// if(user.existUser() == true)
// {
//}
}
}
}
}
Validation does not work either. What is the way to get back on the form what would keep entered value?
Best regards
What is the way to get back on the form what would keep entered value?
Do redirect only when you successfully register user, and just return him to registration page when validation fails.
See also: Problems passing form feedback between controllers to re-display a form error message
I figured out myself. The main thing what was missing is value="${user}" snippet of code in XHTML code. Likewise I needed model.addAttribute("user", user); I wasted a lot of time on this......

Categories

Resources