Navigate to external URL from a backing bean? - java

I'm trying to implement proper logout for my Java EE / JSF2 application.
It requires two things:
I need to logout from JAAS and invalidate the session
I then have to navigate to an external URL to fire Siteminder logout
The Siteminder logout URL (configured on the Policy server -> I cannot change it) is outside my applications context. Eg. if my webapp URL is https://localhost:8080/sm/MyWebApp then the logout URL is https://localhost:8080/anotherwebapp/logout.html.
This is the current local logout code:
public void logout() {
System.out.println("Logging out...");
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
try {
request.logout();
} catch (ServletException e) {
e.printStackTrace();
}
HttpSession session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (session != null) {
session.invalidate();
}
}
And here is the property that produces the logout URL:
public String getLogoutUrl() {
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
String requestServer = request.getServerName();
String requestScheme = request.getScheme();
int serverPort = request.getServerPort();
String logoutUrl = requestScheme + "://" + requestServer + ":" + Integer.toString(serverPort) + "/anotherwebapp/logout.html";
return logoutUrl;
}
However, I cannot find a JSF2 / Primefaces component that can call logout() then open the external URL. For example, if I have:
<h:outputLink value="#{authBean.logoutUrl}" onclick="#{authBean.logout()}">[Logout]</h:outputLink>
then onclick does not seem to be called.
Another way I tried was putting the external URL to the end of the logout function to have it returned as a navigation string but it is not recognized (also tried with "?faces-redirect=true"...).
Any help would be appreciated.

You can also just use ExternalContext#redirect().
public void logout() throws ServletException, IOException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
((HttpServletRequest) ec.getRequest()).logout();
ec.invalidateSession();
ec.redirect("http://example.com/anothercontext/logout");
}
No need for an intermediating page with a meta refresh.

You can create a page logout.xhtml, so the code will look like this:
public String getLogoutUrl() {
return "/logout.jsf";
}
and in the page add:
<META HTTP-EQUIV="Refresh" CONTENT="0;URL=https://localhost:8080/anotherwebapp/logout.html">

Related

How to get page name from WebSphere Portal page?

I am creating a portlet for WebSphere portal 8 and would like to retrieve the page name where my portlet is rendered. This is important because depending on the page, the portlet will server content differently
I've tried to use the NavigationSelectionModel API but do not think I'm using it correctly. I want this code to happen before the view is rendered and I put the code in the doView method. The problem is that I cannot cast a ServletRequest/Response because I only have the RenderRequest and RenderResponse available in the doView method.
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
// Declarations
List<ForeignAuthority> faList = new ArrayList<ForeignAuthority>();
String resp;
// Set the MIME type for the render response
response.setContentType(request.getResponseContentType());
// Check if portlet session exists
ForeignAuthoritiesPortletSessionBean sessionBean = getSessionBean(request);
if (sessionBean == null) {
response.getWriter().println("<b>NO PORTLET SESSION YET</b>");
return;
}
try{
Context ctx = new InitialContext();
NavigationSelectionModelHome home = (NavigationSelectionModelHome)
ctx.lookup("portal:service/model/NavigationSelectionModel");
if (home != null) {
NavigationSelectionModelProvider provider =
home.getNavigationSelectionModelProvider();
NavigationSelectionModel model =
provider.getNavigationSelectionModel((ServletRequest)request, (ServletResponse)response);
for (java.util.Iterator i = model.iterator(); i.hasNext(); )
{
NavigationNode node = (NavigationNode) i.next();
if (i.hasNext()) {
System.out.println(node.getObjectID().getUniqueName());
}
}
}
}catch(Exception e){
e.printStackTrace();
}
PortletRequestDispatcher rd = getPortletContext()
.getRequestDispatcher(getJspFilePath(request, VIEW_JSP));
rd.include(request, response);
}
The expected result would be to retrieve the page name or unique name of the current page that the portlet is rendered on.
You can try whether the below code snippet helps. You can get the URI value and extract the page name from it.
HttpServletRequest httpServletRequest = PortletUtils.getHttpServletRequest(renderRequest);
httpServletRequest.getRequestURI();

Redirect to index.jsp after login using Servlet

I have a servlet to handle /Login.
String tempUsername = request.getParameter("username").trim();
String tempPassword = request.getParameter("password").trim();
String message = null;
if(tempUsername != null && tempPassword != null) {
String username = tempUsername;
String password = tempPassword;
Staff staff = new Staff();
try {
Facade facade = new Facade();
Staff result = facade.getStaff(username, password);
if(result != null) {
// response.sendRedirect(request.getContextPath()+"/Home"); // Success but didn't redirect to `/Home`
System.out.println("Success");
}
else {
// request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
System.out.println("Fail");
}
}
catch(SQLException | NamingException e) {
// SQL Error
}
finally {
request.setAttribute("message", message);
}
}
else {
// Empty field(s)
}
I have another servlet to handle /Home where index.jsp will be displayed if login success.
However, currently if login success, the page is still stay at /Login with only a blank page, instead of redirecting to /Home.
How can I redirect to /Home after login success?
I'm new in using Servlet as well as Eclipse. I just started learning J2EE and Eclipse. Still exploring.
Edit(s):
I changed the forward() and sendRedirect() to println(). When I used the wrong username and password, "Fail" is printed out. But when I used the correct details, there is nothing printed out.
Don't use sendRedirect() - forward() is more appropriate since you're redirecting the request on the same server (using a relative path). If you insist on using sendRedirect() - use the pull URL.
Why do you need that absolutePath thing if you have the mapping of the url of the servlet you want to redirect in the web.xml or as annotation this simple lines shall do the work
RequestDispatcher requestDispatcher=servletContext.getRequestDispatcher("/Home");
requestDispatcher.forward(request, response);
Or this
response.sendRedirect("/Home");

Why is servlet not forwarding after successful AJAX call?

I am attempting to forward the user to an admin.jsp page after they have successfully logged in. The check on the username and password is done via AJAX. All works fine until I attempt to forward them to the admin.jsp page, this is when the AJAX error is thrown.
Here is the AJAX:
$("#loginForm").submit(function(e){
e.preventDefault(); //STOP default action
var postData = $("#loginForm").serializeArray();
var username = $("#username").val();
var password = $("#password").val();
if(username.length > 0 && password.length){
$.ajax(
{
type: "POST",
url : "HomeController",
data : postData,
success: function(data)
{
$("#loginResult").html(data);
},
error: function(jqXHR, textStatus, errorThrown)
{
$("#loginResult").html("<p>ss"+errorThrown+textStatus+jqXHR+"</p>");
}
});
//$("#loginForm").hide();
}else{
$("#loginResult").html("<p>Unable to login: ensure details are correct.</p>");
}
});
and here is the servlet that handles logging in:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String form = request.getParameter("form");
String views = "/WEB-INF/views/";
// check login details
if(form.equals("loginForm")){
String username = request.getParameter("username").trim();
String password = request.getParameter("password").trim();
PrintWriter out = response.getWriter();
password = loginService.hashPassword(password);
boolean isValidUser = loginService.checkUser(username, password);
if(isValidUser){
// set session
HttpSession session = request.getSession();
session.setAttribute("loggedIn", "true");
response.sendRedirect(views + "admin.jsp");
}else{
out.println("Incorrect login details.");
}
}
}
Why is the AJAX call receiving an error and not forwarding to the admin.jsp page?
You can't redirect to resources inside WEB-INF. All resources in that directory are non-visible to the browser, by design.
Either keep the JSP outside of WEB-INF, or forwards to the JSP.
RequestDispatcher view = request.getRequestDispatcher("/WEB-INF/views/admin.jsp");
view.forward(request, response);
Note: forward/include doesn't change the URL in the browser.
Read more...

Avoid double authentication when using custom bean spring security

I have a login form that calls a certain LoginBean, which returns a ajax callback parameter indicating whether the credentials are valid or not.
The code is as follows:
public void doLogin() {
Authentication authenticationRequestToken =
new UsernamePasswordAuthenticationToken(user, password);
try {
Authentication authenticationResponseToken =
authenticationManager.authenticate(authenticationRequestToken);
SecurityContextHolder.getContext().
setAuthentication(authenticationResponseToken);
if (authenticationResponseToken.isAuthenticated()) {
RequestContext context = RequestContext.getCurrentInstance();
FacesMessage msg;
boolean loggedIn = true;
msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", user);
FacesContext.getCurrentInstance().addMessage(null, msg);
context.addCallbackParam("loggedIn", loggedIn);
}
} .authenticate(...) catches ...
// Here I need some code that continue whatever j_spring_security_check
// would do after authenticating.
}
The way my application is working now, after this call to doLogin(), the form is submited to j_spring_security_check, and then the authentication process takes place again, wasting previous work.
I'm trying to find a solution for this, any help is appreciated.
So, the bottom line is that I need something that would simulate what happens when j_spring_security_check is intercepted by the filters (or a way to force this interception explicitly), so the processing would take place behind the button, not after the form is submited.
It will be better if you just forward to the spring security authentication url instead of using the SecurityContextHolder yourself. Look at this code:
public String doLogin() throws ServletException, IOException {
FacesContext context = FacesContext.getCurrentInstance();
String springCheckUrl = this.buildSpringSecurityCheckUrl();
HttpServletRequest request = (HttpServletRequest) context
.getExternalContext().getRequest();
RequestDispatcher dispatcher = request
.getRequestDispatcher(springCheckUrl);
dispatcher.forward((ServletRequest) request,
(ServletResponse) context.getExternalContext.getResponse());
context.responseComplete();
return null;
}
private String buildSpringSecurityCheckUrl() {
StringBuilder springCheckUrl = new StringBuilder(
"/j_spring_security_check").append("?").append("j_username")
.append("=").append(this.userName.trim()).append("&")
.append("j_password").append("=")
.append(this.userPassword.trim());
return springCheckUrl.toString();
}
}

JavaEE + Glassfishv3.0.1: Losing session attribute (SessionId is not the same between request)

I have a home.jsf that invoke a login servlet that look into database and query out the user object given the username and password. Then I save that user object into session under attribute name user, like this request.getSession().setAttribute("user", user);
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
boolean remember = "true".equals(request.getParameter("remember"));
//Hashing the password with SHA-256 algorithms
password = hash(password);
HttpSession s = request.getSession(false);
if (s != null) {
logger.log(Level.INFO, "Id: {0}", s.getId());
}
User user = scholarEJB.findUserByUserNamePassword(username, password);
try {
if (user != null) {
request.login(username, password);
request.getSession().setAttribute("user", user);
if (remember) {
String uuid = UUID.randomUUID().toString();
UserCookie uc = new UserCookie(uuid, user.getId());
scholarEJB.persist(uc);
Helper.addCookie(response, Helper.COOKIE_NAME, uuid, Helper.COOKIE_AGE);
}else{
//If the user decide they dont want us to remember them
//anymore, delete any cookie associate with this user off
//the table
scholarEJB.deleteUserCookie(user.getId());
Helper.removeCookie(response, Helper.COOKIE_NAME);
}
response.sendRedirect("CentralFeed.jsf");
}else{
response.sendRedirect("LoginError.jsf");
}
} catch (Exception e) {
response.sendRedirect("LoginError.jsf");
}
Then I have a Filer that map to all my secured page, that will try to retrieve the user object from the session, otherwise, redirect me to home.jsf to login again
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession s = request.getSession(false);
if (s != null) {
logger.log(Level.INFO, "Id Before: {0}", s.getId());
}
User user = (User) request.getSession().getAttribute("user");
s = request.getSession(false);
if (s != null) {
logger.log(Level.INFO, "Id After: {0}", s.getId());
}
if (user == null) {
String uuid = Helper.getCookieValue(request, Helper.COOKIE_NAME);
if (uuid != null) {
user = scholarEJB.findUserByUUID(uuid);
if (user != null) {
request.getSession().setAttribute("user", user); //Login
Helper.addCookie(response, Helper.COOKIE_NAME, uuid, Helper.COOKIE_AGE);
} else {
Helper.removeCookie(response, Helper.COOKIE_NAME);
}
}
}
if (user == null) {
response.sendRedirect("home.jsf");
} else {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(req, res);
}
Now as you see here, I manipulate some Cookie as well, but that is only happen when I check remember me. So now I am in CentralFeed.jsf, but then any request that I send from here will bring back to home.jsf to login again. I walk through a debugger, so when I first login, the first time I get into the Filter, i successfully retrieve the user object from session by request.getSession().getAttribute("user");. But after that, when I get back in the filter, I no longer the session attribute user anymore. I set session timeout to be 30 min in my web.xml
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
EDIT
Now when I print out the session Id between request, it is fact different session id, but I have no idea why? please help.
EDIT2
#BalusC: I actually did invalidate the session. Back then, you show me how to force a logout when user log in somewhere else (http://stackoverflow.com/questions/2372311/jsf-how-to-invalidate-an-user-session-when-he-logs-twice-with-the-same-credentia). So inside User entity i have this
#Entity
public class User implements Serializable, HttpSessionBindingListener {
#Transient
private static Map<User, HttpSession> logins = new HashMap<User, HttpSession>();
#Override
public void valueBound(HttpSessionBindingEvent event) {
HttpSession session = logins.remove(this);
if (session != null) {
session.invalidate(); //This is where I invalidate the session
}
logins.put(this, event.getSession());
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
logins.remove(this);
}
}
In the valueBound method, I did invalidate the session, when I comment it out, everything work. I walk through the debugger, and here is what happen. When I first log in, the LoginServlet catch it. Then the line request.getSession().setAttribute("user", user); invoke the method valueBound. Then the Filter got called, and the line chain.doFilter(req, res); invoke the valueBound method again, this time, session is not null so it get in the if and session.invalidate. I comment the session.invalidate out and it work. But as u might have guess, I cant force a log out when user login somewhere else. Do you see a obvious solution for this BalusC?
The HTTP session is maintained by the JSESSIONID cookie. Ensure that your Helper.COOKIE_NAME doesn't use the same cookie name, it will then override the session cookie.
If that is not the case, then I don't know. I would use Firebug to debug the HTTP request/response headers. In a first HTTP response on a brand new session you should be seeing the Set-Cookie header with the JSESSIONID cookie with the session ID. In all subsequent requests within the same session, you should be seeing the Cookie header with the JSESSIONID cookie with the session ID.
A new session will be created when the Cookie header is absent or contains a JSESSIONID cookie with a (for the server side) non-existing session ID (because it's been invalidated somehow), or when the server has responded with a new Set-Cookie header with a different session ID. This should help you in nailing down the culprit. Is it the server who generated a new session cookie? Or is it the client who didn't send the session cookie back?
If it was the server, then somewhere in the server side the session has been expired/invalidated. Try putting a breakpoint on HttpSession#invalidate() to nail it further down.
If it was the client (which would be very weird however, since it seems to support cookies fine), then try to encode the redirect URL to include the JSESSIONID.
response.sendRedirect(response.encodeRedirectURL(url));
Try with different clients if necessary to exclude the one and other.
look at the JSessionID param in your request. If it changes that means you are losing your session (browser is telling your Server its another session). Dont know why its happening but propably is something you are doing (open another window, change servlet context and come back, change server in some request... etc.).
Please post more information if you confirm that

Categories

Resources