session handling in JSF 1.2 - java

How do we handle session variables (add/fetch) in JSF 1.2?
A scenario: Consider a login screen where the user logs in successfully, the user model is stored in session. The user modes contains the user role. Next time onwards, for every user action, check the user role from the user model and display the form accordingly. In such a case how to add the user odel in session and how to etrieve it every time from the session?
Previously I have worked in Struts 1.2 where in the execute method, we have a request e=which is used to get the session and access the session variables also. But I am not sure how to achieve th same in JSF 1.2.
Is the only way achieveable is to add the managed bean in the session scope in the faces-config.xml file?
Please help me out with the session handling concepts in JSF 1.2.

The session scope is programmatically available by ExternalContext#getSessionMap() which delegates under the covers to HttpSession#get/setAttribute().
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
// ...
You can of course also just put a managed bean in the session scope. It's accessible from other managed beans by <managed-property> (or just a traversal of the session map using the managed bean name as map key).

I think you can use Java EE filters for this mechanism.
Filters are controlled by Servlet Container and runs first on an action depending on your web.xml order.
Add a servlet filter to your project.
public class YourFilter implements Filter {
public static final String USER = "USER_SESSION_KEY";
public void doFilter(ServletRequest req, ServletResponse response, FilterChain filterChain)
{
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession(true);
String servletpath = request.getServletPath();
if(!servletpath.contains("login.xhtml")) //exclude your login page and other pages required to pass this filter.
{
if (session.getAttribute(USER) != null)
{
//Control your authentication and roles.
}
else
{
//There is no user in the session.
}
}
}
filterChain.doFilter(request, response);
}
Add your filter to your web.xml
<filter>
<filter-name>YourFilter</filter-name>
<filter-class>Package.YourFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>YourFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
Secondly, put your User class to the session inside a JSF action.
public void userAction()
{
User user = new User();
//Build your User Class
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
request.getSession(false).setAttribute("USER", user);
}
P.S. : User class is a user defined POJO class. you should implement it according to your needs.
public class User
{
private String username;
//Other properties and getter setter methods required.
}
If you want to implement this mechanism inside JSF context. You can build the same logic by implementing JSF phase listeners.

Related

Is ServletRequest::setAttribute safe in terms of web service security?

Short Version
Is javax.servlet.ServletRequest's method setAttribute(<key>, <Object>) only used as a means of passing objects between methods in Java code?
Long version
Let's say I have a javax.servlet.Filter implementation to handle all logged in users' authentication using cookies:
in Spring Boot
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class AuthFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
Cookie[] cookies = null;
if (request instanceof HttpServletRequest) {
cookies = ((HttpServletRequest) request).getCookies();
}
Optional<User> user = mySessionAuthMethod(cookies);
if (user.isPresent()) {
request.setAttribute("user", user.get());
}
chain.doFilter(request, response);
}
}
Then later, I can avoid manual authentication in all of the Web API methods, and just check the user attribute. Example of a #RestController's method:
#RequestMapping(value = "/profile")
#CrossOrigin(origins = {MyProperties.ORIGIN}, allowCredentials = "true")
public ResponseEntity getProfile(HttpServletRequest request, HttpServletResponse response) {
String user = request.getAttribute("user");
if (user != null) {
return myGetProfileResponse(user);
}
return myNotLoggedInResponse();
}
My questions are:
Is this form of authentication secure? What I mean is, are the attributes in the ServletRequest only added and used in Java for communication between methods, or could they be added to the request already before reaching the server?
Is this way of authentication using Filters a good practice to avoid duplicate code?
Additional Explanation
The real reason of doing this is not only authentication. I have also Filters which need to process each and every request and pass objects to the Controllers. What I definitely want is that none of these objects and information can be forged even by a person who knows the implementation of the system.
I think I have found the answer from the documentation of getAttribute
Attributes can be set two ways. The servlet container may set attributes to make available custom information about a request. For example, for requests made using HTTPS, the attribute javax.servlet.request.X509Certificate can be used to retrieve information on the certificate of the client. Attributes can also be set programatically using ServletRequest#setAttribute. This allows information to be embedded into a request before a RequestDispatcher call.
So according to this (if there is no missing information), it should be completely safe to pass custom objects and know that they were always created by the server.

How to secure session variable in HttpSession using java servlets

I think there should a way to set session variable with defined scope in pure java Servlet without using other library like jsf or springframework so that visibility of session variable can be restricted.
public void doGet(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
String userId = (String)request.getAttribute("userId");
session.setAttribute("userId", userId);
}
I found ServletContext
ServletContext context = request.getSession().getServletContext();
context.setAttribute("userId", userId);
but this one doesnot seem to provide session scope flexibility.
You've found it. Set a session attribute. The scope of a session attribute is the scope of a session, which is a single user.
The portlet scope just controls whether the attribute is confined to the current portlet or is visible to all portlets. It's still within the user session. If you need to implement that feature, just bind a Map into the session under the name of the portlet, and have each portlet look in its own Map.
If you set a context attribute it will be visible to all users.

Access PortletSession attributes (set by interceptor) from the controller (Spring Portlet MVC)

I'm new to Spring Portlet MVC, but I've been studying hard on it in the last few days.
The context of my problem is the following
I have a Spring Portlet MVC portlet with a single controller.
The portlet is configured to call an HandlerInterceptor (method 'preHandleRender') anytime a user wants to access to a resource.
The interceptor checks if the user is authenticated, if not, it retrieves the user's Liferay credentials to manage authentication on a number of other webservices (not interesting right now).
After this, the interceptor stores the user data inside the PortletSession.
Now, how am I supposed to retrieve the user data stored in the PortletSession by the interceptor from inside the controller??
sessionInterceptor.preHandleRender
#Override
public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler) throws Exception {
PortletSession session = request.getPortletSession(true);
.
.
.
session.setAttribute("userProfile", userProfileDomain,PortletSession.APPLICATION_SCOPE);
.
.
.
return true;
}
ViewController class
#Controller("viewController")
#RequestMapping(value = "view")
public class ViewController {
//#Autowired
private WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
#RenderMapping
public String setModelAndView(RenderRequest request, ModelMap tgtModel) {
logger.debug("<< | >> Starting.");
PortletConfiguration conf = PortletConfiguration.getInstance();
.
.
}
}
I am ready to give further information about my code if requested.
I was able to solve the problem and to identify my error.
In the interceptor, as I showed in my question, I set the session attribute "userProfile" in the PortletSession.APPLICATION_SCOPE.
session.setAttribute("userProfile", userProfileDomain,PortletSession.APPLICATION_SCOPE);
As for the controller, I understood you have multiple options:
Pass the request (RenderRequest, in my case) as a parameter, the obtain the session (PortletSession, in my case) from the request and then retrieve the attribute from the session.
Pass directly the session as a parameter and then retrieve the attribute from it.
However, whether you take the first or the second road, if you use the following instruction in the controller
session.getAttribute("userProfile");
you wont get anything because the attribute was set in PortletSession.APPLICATION_SCOPE.
The correct instruction is:
session.getAttribute("userProfile",PortletSession.APPLICATION_SCOPE);
Spring MVC wires the PortletSession if you specify it as parameter.
#RenderMapping
public String setModelAndView(RenderRequest request, PortletSession session, ModelMap tgtModel) {
logger.debug("<< | >> Starting.");
PortletConfiguration conf = PortletConfiguration.getInstance();
.
.
}
See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/portlet.html#portlet-ann-requestmapping-arguments for the supported types.

Servlet filter (autologin) precedence over declarative security checks

Short question. How is it possible to execute servlet filters before any declarative security check is performed?
Long question. For my web application I'm trying to manage all my security needs using server declarative security: I have set a security constraint on <url-pattern>/secure/*</url-pattern> with <auth-method>FORM</auth-method> and <form-login-page>/sign-in.xhtml</form-login-page>.
In order to provide a (cookie-based) "remember me" function, I have set a servlet filter which intercepts each request, checks if the user is not logged in, checks if he can be logged in automatically (via cookie), eventually logs him in using servlet based login.
<filter-mapping>
<filter-name>CustomLoginFilter</filter-name>
<url-pattern>*.xhtml</url-pattern>
</filter-mapping>
Now, if the user opens his browser and connects to mysite.com everything just works. But if the user opens his browser and makes a straight request to something like mysite.com/secure/secret.xhtml I observe the following behaviour:
GET /secure/secret.xhtml
the backing beans of log-in.xhtml are instantiated (FacesContext is available)
the CustomLoginFilter.doFilter( ) gets called, (FacesContext is NULL)
This obviously hinders all the process. I cannot find any way to give precedence to my CustomLoginFilter over the server "declarative security filter" (or whatever); changing the web.xml order of declarations doesn't help too... any ideas? Thank you!
How is it possible to execute servlet filters before any declarative security check is performed?
That's not possible due to specification and security restrictions.
Your best bet is a hook on preRenderView event in the login page and use programmatic login by the new Servlet 3.0 HttpServletRequest#login() method.
E.g.
<f:event type="preRenderView" listener="#{authenticator.checkAutoLogin}" />
with something like
public void checkAutoLogin() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
Cookie autoLogin = externalContext.getRequestCookieMap().get("autoLoginCookieName");
if (autoLogin != null) {
User user = decryptCookieValueAndExtractUser(autoLogin.getValue()); // Yes, it must be encrypted! Otherwise a too easy hack.
if (user != null) {
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
try {
request.login(user.getName(), user.getPassword());
String originalRequestURI = externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
externalContext.redirect(originalRequestURI != null ? originalRequestURI : "someDefaultIndex.xhtml");
} catch (ServletException e) {
// Login failed. It's up to you how to handle it.
}
}
}
}

JAAS, doing login from outside the container

I have an application with JAAS and i need do an external login from the legacy, so i wrote a servlet with this code bellow, it works fine, but when i do another submit the JAAS tries authenticate again and has failure, and the user is redirected to login page.
here is doPost method:
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
NfWebCallbackHandler callbackHandler = new NfWebCallbackHandler(req);
LoginContext loginContext = null;
boolean loginSuccess = true;
try {
loginContext = new LoginContext("MyLoginContext", callbackHandler);
loginContext.login();
} catch (LoginException e) {
loginSuccess = false;
RequestDispatcher dispatcher = req
.getRequestDispatcher("/login.jsf");
dispatcher.forward(req, resp);
e.printStackTrace();
}
if (loginSuccess) {
RequestDispatcher dispatcher = req.getRequestDispatcher(req
.getParameter("targetUrl"));
dispatcher.forward(req, resp);
}
}
any idea is welcome! thanks!
When you use a JAAS Login Module outside the purview of the container (or at least in a mannaer unrecognizable to the container), the container will not be aware of the fact that the Subject and the set of Principals (associated with the subject) are to be stored and managed by the container.
When you use one of the container-managed authentication schemes, the container actually stores the subject in the Session implementation class (at least in Tomcat 6, this is true), in a manner that is completely opaque to the developer; using getAttribute() on the session object will never return the Subject, and neither can use setAttribute() to override the Subject. When needed, the subject is retrieved from this session field and used for various purposes by the container; for instance, when you invoke getUserPrincipal() or getRemoteUser() on the HttpServletRequest object, the Principal associated with the Subject is actually used to return the result.
If you need to get the container to do all this heavy-lifting for you, then you need to use the JAAS Login module in conjunction with a container managed authentication scheme. If you do not want to go this way, then you'll need to "remember" the Subject and the Principals for the duration of the session; not to forget, all of this has to be done in a secure manner.
I forgot to register my solution for this case, i used this class:
org.jboss.web.tomcat.security.login.WebAuthentication
i wrote something like that:
WebAuthentication webAuthentication = new WebAuthentication();
req.getSession().setAttribute("webAuthentication", webAuthentication);
I dont remember where i found this, but was very useful!
Thanx Vineet Reynolds, the only one who tried to help me hehehe

Categories