i have implemented jsf phase listener which check if user looged in or not, and if not redirect user to login page.
Now, i want to implement phase listener in case where user manualy input
page name in address bar. In this case phase listener must automatic
redirect user to login page and destroy session.
How do that in JSF ?
Just use a simple servlet Filter which is mapped on a common URL pattern of the restricted pages like /app/*, /pages/*, /secured/*, etc. Here's a kickoff example assuming that you've a #SessionScoped #ManagedBean UserManager.
#WebFilter(urlPatterns={"/app/*"})
public class AuthenticationFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
UserManager userManager = (session != null) ? (UserManager) session.getAttribute("userManager") : null;
if (userManager == null || !userManager.isLoggedIn()) {
response.sendRedirect(request.getContextPath() + "/login.xhtml"); // No logged-in user found, so redirect to login page.
} else {
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
// ...
}
I am on JSF 1.2 and did that this way:
public void beforePhase(PhaseEvent event)
{
FacesContext fCtx = FacesContext.getCurrentInstance();
String actualView = null;
actualView = event.getFacesContext().getApplication().getViewHandler().getResourceURL(fCtx, fCtx.getViewRoot().getViewId());
//actualView is the page the user wants to see
//you can check, if the user got the permission, is logged in, whatever
}
public PhaseId getPhaseId()
{
return PhaseId.RENDER_RESPONSE;
}
Related
Hi guys I am building a Java web app using JSF. For authentication I have used Apache Shiro.I have built a logout button which is calling the logout method of shiro and then I redirect the user to login page. But If I click back button the user can navigate into pages. I read about this and I realized that I had to implement my own custom filter. This is the code of the filter :
import al.ikubinfo.ipermit.bpmn.model.entities.UserEntity;
import al.ikubinfo.ipermit.bpmn.services.UserService;
public class LoginFilter implements Filter {
private static final String LOGIN_VIEW = "/login.xhtml";
#EJB
private UserService userService;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
UserEntity currentUser = userService.getCurrentUser();
if (currentUser == null) {
httpServletResponse.sendRedirect(httpServletRequest.getServletContext().getContextPath() + LOGIN_VIEW);
}
else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
}
I have also included it in the web.xml but it doesnt work. The application start successfully but noe view is opened. Can someone help me please?
When using the back button you are seeing a cached version of the page. The page is cached locally in the browser.
After logout you must be going to login page
Use following javascript on this page
var url = window.location.href;
window.history.go(-window.history.length);
window.location.href = url;
Also try to insert
<META Http-Equiv="Cache-Control" Content="no-cache">
<META Http-Equiv="Pragma" Content="no-cache">
<META Http-Equiv="Expires" Content="0">
into jsp pages so that browser dont cache the pages.
I'm currently using a Filter to check for SSO authentication. (SSO is considered authenticated if the request header contains the variable "Proxy-Remote-User").
if (!(isSsoLoggedIn(request)) {
response.sendRedirect(ERROR_PAGE);
return;
} else {
chain.doFilter(req, res);
}
private boolean isSsoLoggedIn(HttpServletRequest request) {
return request != null && request.getHeader("Proxy-Remote-User") != null
&& !request.getHeader("Proxy-Remote-User").equals("");
}
Now, once the user is authenticated, I want to pass that variable (which is an email address) to JSF. I do that with a session-scoped bean:
#PostConstruct
public void init {
Map<String, String> requestHeaderMap = FacesContext.getCurrentInstance().getExternalContext().getRequestHeaderMap();
String email = requestHeaderMap.get("Proxy-Remote-User");
user = getPersonFromDB(email);
}
This seems simple enough, but I'm not sure if its the "right" way to do this. It doesn't seem correct to rely on a bean's instantiation to verify authentication.
One idea I just had: Use a CDI session-scoped bean and #Inject it into the Filter. Then, you could have the filter itself check for a valid user and, if valid, set it in the session-scoped bean, otherwise forward it to an error page.
Does that sound like a valid solution?
Another approach could be to have every page check for authentication, before the view is rendered, with a view param as mentioned here:
JSF calls methods when managed bean constructor sends 404 ERROR CODE
<f:metadata>
<f:viewAction action="#{bean.checkForValidUser}" />
</f:metadata>
The only problem I have for this is...this would require copying/pasting the same code to every page which seems redundant (or at least a template for them all to use).
Here is the answer I came up with (thanks to some tips from #BalusC).
I check to see if developer login is enabled or SSO has been authenticated. Once I have the email address, I see if its a valid user, verify the JSF session contains the right user, and, if so, forward them on their way.
/**
* This filter handles SSO login (or developer login) privileges to the web
* application.
*/
#WebFilter(servletNames = "Faces Servlet")
public class SecurityFilter implements Filter {
#Inject
private SessionManager sessionManager;
#EJB
private PersonWriteFacadeRemote personFacade;
private HttpServletRequest currentRequest;
private HttpServletResponse currentResponse;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
currentRequest = (HttpServletRequest) req;
currentResponse = (HttpServletResponse) res;
HttpSession session = currentRequest.getSession();
String requestedPage = currentRequest.getRequestURI();
// check if the session is initialized
// if not, initialize it
if (!isSessionInitialized()) {
Person user = getCurrentUser();
// if we can't figure out who the user is, then send 401 error
if (user != null) {
initializeSession(user);
} else {
currentResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// if it is initialized, check if it actually matches the current
// user
// if not, invalidate the session and redirect them back to the page
// to reinitialize it
} else if (!isSessionCurrentUsers()) {
session.invalidate();
currentResponse.sendRedirect(requestedPage);
return;
}
chain.doFilter(req, res); // If all looks good, continue the request
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
private Person getCurrentUser() {
try {
return personFacade.createFromEmail(getUserEmail());
} catch (InvalidAttributesException ex) {
Logger.getLogger(SecurityFilter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
private String getUserEmail() {
return isDevLoginEnabled() ? getUserEmailFromJndi() : getUserEmailFromSso();
}
private String getUserEmailFromJndi() {
return JNDI.lookup("devLoginEmail");
}
private String getUserEmailFromSso() {
return currentRequest != null && currentRequest.getHeader("Proxy-Remote-User") != null
&& !currentRequest.getHeader("Proxy-Remote-User").equals("")
? currentRequest.getHeader("Proxy-Remote-User") : null;
}
private boolean isDevLoginEnabled() {
Boolean devLoginEnabled = JNDI.lookup("devLoginEnabled");
return (devLoginEnabled != null ? devLoginEnabled : false);
}
private boolean isSessionInitialized() {
return sessionManager.getUser() != null;
}
private void initializeSession(Person user) {
sessionManager.initializeSession(user);
}
private boolean isSessionCurrentUsers() {
return sessionManager.getUser() != null && sessionManager.getUser().getEmail() != null
&& sessionManager.getUser().getEmail().equals(getUserEmail());
}
}
while logout i did removed session object and invalidated session also as like below
public String logout() throws IOException {
logger.info("logout() : satarted----- ");
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.getSessionMap().remove("visitorComponent");
System.out.println("*************_->"+ec.getSessionMap().remove("visitorComponent"));
ec.invalidateSession();
ec.redirect(ec.getRequestContextPath() + "/logout.xhtml");
return null;
// return "logout?faces-redirect=true";
}
But still in filter class its giving values, filter class code like below
public class AuthorizationFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Cache-Control", "no-cache,no-store,must-revalidate"); // HTTP 1.1
httpResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0
httpResponse.setDateHeader("Expires", 0);
if (session.getAttribute("visitorComponent") != null) {
System.out.println("-sdf>"+((VisitorComponent) session.getAttribute("visitorComponent")).getAdmin());
}
System.out.println("->"+session.getAttribute("visitorComponent"));
System.out.println("=url>"+req.getRequestURI());
System.out.println("=>"+req.getRequestURI().endsWith("login.xhtml"));
if (session.getAttribute("visitorComponent") != null || req.getRequestURI().endsWith("index.xhtml")) {
chain.doFilter(request, httpResponse);
} else {
System.out.println("---in else--");
// HttpServletResponse res = (HttpServletResponse) response;
httpResponse.sendRedirect("index.xhtml");
return;
}
}
Could you please help any one, what I need to do?
Finally I found solution but side effects are there.
My solution is, previously I was not kept login object manually because my login class in session scope. If i do in this way its not clear the object after invalidate also because while starting application login class instantiated.
#ManagedBean(name = "visitorComponent")
#SessionScoped
public class VisitorComponent {
Admin admin = new Admin();
public String login() {
// some code to verify login details
this.admin = adminService.getAdminObject(adminId);
}
Now i did manually by get session object map and put my login object in session map.
#ManagedBean(name = "visitorComponent")
#SessionScoped
public class VisitorComponent {
Admin admin = new Admin();
public String login() {
// some code to verify login details
this.admin = adminService.getAdminObject(adminId);
// Session object creating to get the session values
ExternalContext externalContext = FacesContext.getCurrentInstance()
.getExternalContext();
Map<String, Object> sessionMap = externalContext.getSessionMap();
sessionMap.put("abcadminBean", this.admin);
}
Now its working fine by invalidate but problem is in my login page
i have
I have doubt in my filterclass, that is like below
public class AuthorizationFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
if (session.getAttribute("abcadminBean") != null || req.getRequestURI().endsWith("index.xhtml")) {
chain.doFilter(request, response);
} else {
FacesContext fc = FacesContext.getCurrentInstance();
if (fc == null) {
// Create new Lifecycle.
LifecycleFactory lifecycleFactory = (LifecycleFactory)
FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
// Create new FacesContext.
FacesContextFactory contextFactory = (FacesContextFactory)
FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
fc = contextFactory.getFacesContext(
((HttpServletRequest) request).getSession().getServletContext(), request, response, lifecycle);
}
System.out.println("fc->"+fc);
ExternalContext ec = fc.getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/index.xhtml");
// HttpServletResponse res = (HttpServletResponse) response;
// ((HttpServletResponse) response).sendRedirect("index.xhtml");
return;
}
}
Here I am redirecting my page, I thought it is the problem
Could you please any one help me, What i need to do for my UI changes ?
Finally I caught solution.
Why because it is not loading all primefaces UI effects is,
For every request our filter is checking so in Filter class we have to write condition to allow our CSS and JS file as like below
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
if (session.getAttribute("loginDetails") != null
|| session.getAttribute("empLoginDetails") != null
|| req.getRequestURI().endsWith("index.xhtml")
|| req.getRequestURI().endsWith("forgetpass.xhtml")
|| req.getRequestURI().endsWith("empLogin.xhtml")
|| req.getRequestURI().endsWith("logout.xhtml")
|| req.getRequestURI().endsWith("ajax-loader.gif.xhtml")
|| req.getRequestURI().contains(".js")
|| req.getRequestURI().contains(".css")) {
chain.doFilter(request, response);
} else {
FacesContext fc = FacesContext.getCurrentInstance();
if (fc == null) {
// Create new Lifecycle.
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory
.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
// Create new FacesContext.
FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder
.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
fc = contextFactory.getFacesContext(
((HttpServletRequest) request).getSession()
.getServletContext(), request, response,
lifecycle);
}
RequestDispatcher dispatcher = request
.getRequestDispatcher("/index.xhtml");
dispatcher.forward(request, response);
return;
}
Now my application is working fine with filter class
Good Day!
Im having a problem with my log in in JSF, it seems that after the log in, the session becomes null. It logs me in the first, but when i hit refresh or go to another page it redirects to login. Hope anybody can help with this. Below are my codes.
Thanks
Filter Class:
#Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) arg0;
HttpSession session = request.getSession();
User user = (session != null) ? (User) session.getAttribute("userBean") : null;
if(user != null){
arg2.doFilter(arg0, arg1);
}else{
HttpServletResponse response = (HttpServletResponse) arg1;
response.sendRedirect(request.getContextPath() + "/login.xhtml");
}
}
Login from User Managed Bean Class:
public void login(){
UserDAO action = new UserDAO();
try{
User u = action.login(username, password);
if(u == null){
FacesContext.getCurrentInstance().getExternalContext().redirect(showLogin() + ".xhtml?ref=err");
}else{
FacesContext.getCurrentInstance().getExternalContext().getSession(true);
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("userBean", u);
FacesContext.getCurrentInstance().getExternalContext().redirect("pages/dashboard.xhtml");
}
}catch(Exception e){
e.printStackTrace();
}
}
My web.xml:
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>rpt.filters.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/pages/*</url-pattern>
</filter-mapping>
I try to create login form in web application.
in JSP page I can use
<%
String name = request.getParameter( "username" );
session.setAttribute( "theName", name );
%>
but now I am using JSF /Facelets for web application
I don't know how to create session in JSF Backing bean for client and check if user is logged in or not so it will redirect into login page.
who can help me give me link tutorial for these problem ?
thank you before
Now I have little problem with mapping into web.xml
code snipped of class Filter
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
LoginController controller = (LoginController) req.getSession()
.getAttribute("loginController");
if (controller == null || !controller.isLoggedIn()) {
res.sendRedirect("../admin/login.xhtml");
} else {
chain.doFilter(request, response);
}
}
and in web.xml I map with <fitler> tag
<filter>
<filter-name>userLoginFilter</filter-name>
<filter-class>com.mcgraw.controller.UserLoginFilter</filter-class>
<init-param>
<param-name>loginPage</param-name>
<param-value>/login.xhtml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>userLoginFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
I have one folder admin in web project and I check if the user is not logged in with admin permission to not access page (I can do the permission check) but when I use the filter the browser doesn't understand url ??
no StackTrace show when the browser doesn't understand url
Error shown on Firefox
The page isn't redirecting properly
on IE it loading ... loading . .. non-stop
now I change condition which check if req.getPathInfo.startsWith("/login.xhtml") it will do chain
I have 2 idea but it response 500 HTTP STATUS
if (controller == null || !controller.isLoggedIn()) {
res.sendRedirect("../admin/login.xhtml");
if(req.getPathInfo().startsWith("/login.xhtml")){
chain.doFilter(request, response);
}
} else {
chain.doFilter(request, response);
}
===============
if (controller == null || !controller.isLoggedIn()) {
if (!req.getPathInfo().startsWith("/login.xhtml")) {
res.sendRedirect("../admin/login.xhtml");
} else {
chain.doFilter(request, response);
}
} else {
chain.doFilter(request, response);
}
======================
update Class loginController
package com.mcgraw.controller;
import com.DAO.UserBean;
import com.entity.IUser;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
/**
* #author Kency
*/
#ManagedBean
#SessionScoped
public class LoginController implements Serializable {
#EJB
private UserBean userBean;
private IUser user;
private boolean admin;
private boolean mod;
private PasswordService md5;
/** Creates a new instance of LoginController */
public LoginController() {
user = new IUser();
md5 = new PasswordService();
}
// getter / setter
public boolean isMod() {
return mod;
}
public void setMod(boolean mod) {
this.mod = mod;
}
public IUser getUser() {
return user;
}
public void setUser(IUser user) {
this.user = user;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public String cplogin() {
String md5Password = md5.md5Password(user.getPassword());
if (userBean.userLogin(user.getUsername(), md5Password) != null) {
if (user.getUsername() != null || md5Password != null) {
user = userBean.userLogin(user.getUsername(), md5Password);
if (user.getGroups().getAdmin() != null) {
setAdmin(user.getGroups().getAdmin());
}
if (user.getGroups().getMods() != null) {
setMod(user.getGroups().getMods());
}
if (isAdmin() == true || isMod() == true) {
return "home";
} else {
return "login";
}
} else {
return "login";
}
} else {
return "login";
}
}
public String logout() {
user = null;
return "login";
}
public boolean isLoggedIn() {
return user != null;
}
}
I have new problem if render JSF taglib with method loggedIn, in index page (not in admin folder) user doesn't login can see what I render example, <== this like if user doesn't login user can't see but why can he see it?
You can in JSF get/set HTTP session attributes via ExternalContext#getSessionMap() which is basically a wrapper around HttpSession#get/setAttribute().
#Named
#RequestScoped
public class LoginController {
private String username;
private String password;
#EJB
private UserService userService;
public String login() {
User user = userService.find(username, password);
FacesContext context = FacesContext.getCurrentInstance();
if (user == null) {
context.addMessage(null, new FacesMessage("Unknown login, try again"));
username = null;
password = null;
return null;
} else {
context.getExternalContext().getSessionMap().put("user", user);
return "userhome?faces-redirect=true";
}
}
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "index?faces-redirect=true";
}
// ...
}
In the Facelets page, just bind the username and password input fields to this bean and invoke login() action accordingly.
<h:form>
<h:inputText value="#{loginController.username}" />
<h:inputSecret value="#{loginController.password}" />
<h:commandButton value="login" action="#{loginController.login}" />
</h:form>
Session attributes are directly accessible in EL. A session attribute with name user is in EL available as #{user}. When testing if the user is logged in some rendered attribute, just check if it's empty or not.
<h:panelGroup rendered="#{not empty user}">
<p>Welcome, #{user.fullName}</p>
<h:form>
<h:commandButton value="logout" action="#{loginController.logout}" />
</h:form>
</h:panelGroup>
The logout action basically just trashes the session.
As to checking an incoming request if a user is logged in or not, just create a Filter which does roughly the following in doFilter() method:
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURI = request.getContextPath() + "/login.xhtml";
boolean loggedIn = session != null && session.getAttribute("user") != null;
boolean loginRequest = request.getRequestURI().equals(loginURI);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER);
if (loggedIn || loginRequest || resourceRequest) {
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURI);
}
}
Map it on an url-pattern covering the restricted pages, e.g. /secured/*, /app/*, etc.
See also:
How to handle authentication/authorization with users in a database?
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same
Try this in your backing bean when a request is received (like in an action method):
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpSession session = request.getSession();
Then you can work with the request and session objects just like you used to with JSPs, setting attributes and so on.
You might also want to take a look at my related question about checking the client session in a servlet Filter. You could write a similar Filter to check for the user login in their HttpSession and then do a redirect (or RequestDispatch like I ended up doing) to your login page if needed.