I am doing up this application using mainly JSP and Tomcat as my server.
I am trying to set up authorization levels whereby certain class of users can do certain stuff(access certain pages like creating new records or searching past records), eg creating new users should only be done by an admin.
What i have done now is to first:
<%
String user = request.getParameter("name");
String pwd = request.getParameter("password");
String sql = "select * from members where name = ? and password = ?";
int role = 0;
// since execute returns an int of 1 or 0, we can use it for our if-else statement
if (BaseDAO.check(sql, user, pwd) != 0) {
session.setAttribute("user", user);
role = BaseDAO.checkRole(sql, user, pwd);
session.setAttribute("role", role);
response.sendRedirect("frameMgr.jsp");
} else {
session.setAttribute("login", 0);
response.sendRedirect("loginPage.jsp");
}
%>
After login is successful, I would then pull the value for role from the database and set it to session attribute. Then later at my createNewUser page, i have this to check if the user is of the assigned role
<%
int role = (Integer) session.getAttribute("role");
// only allow people with admin role to create more accounts
if (role != 5) {
response.sendRedirect("frameContent.jsp"); //back to homepage
}
%>
However i realised that this method is inefficient as i would have to put the check on every page and if there are changes in the future i would have to go page by page to change the code. is there a method to control all the authorization levels on one page alone? rather than having to do this on all my jsp files
Best you can do is to use HTTP filter. Every request going to be validated with your filter. Of course this will only prevent user to access resources(page/images etc.) But it does not serve as authorizer for your methods and user interactions.
#WebFilter("/*") Every resources
#WebFilter("/user/*") Resources under user folder
#WebFilter("/admin/*") Resources under admin folder
#WebFilter("/what/ever/*")
Example:
#WebFilter("/user/*")
public class UserFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse res = (HttpServletResponse) servletResponse;
if (/*Check if user is logged*/) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
res.sendRedirect(req.getContextPath() + "/login.jsp");
}
}
#Override
public void destroy() {
}
}
Related
I've a filter used for the login. It performs a textual checking, on fields "Username" and "Password". If and only if the textual checking is correctly done the request goes to the Servlet. This latter performs the control that has to interact with the Database. Is this chain correct?
Preface: I gather you're using homegrown login instead of container managed login. For all ways, see How to handle authentication/authorization with users in a database?
The filter (the interceptor) shouldn't check the validity of the username/password combo. That's the responsibility of the servlet (the controller).
The filter should merely check if the user is logged-in or not (usually by just checking the presence of a session attribute) and then continue the request or block it by redirecting back to the login page.
#WebFilter("/*")
public class LoginFilter implements Filter {
#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";
boolean loggedIn = session != null && session.getAttribute("user") != null;
boolean loginRequest = request.getRequestURI().equals(loginURI);
if (loggedIn || loginRequest) {
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURI);
}
}
// ...
}
The servlet should collect the submitted data, find the associated User in database and if found then store it as a session attribute and then redirect to the home page, else redisplay the form with validation errors.
#WebServlet("/login")
public class LoginServlet extends HttpServlet {
#EJB
private UserService userService;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
Map<String, String> messages = new HashMap<String, String>();
if (username == null || username.isEmpty()) {
messages.put("username", "Please enter username");
}
if (password == null || password.isEmpty()) {
messages.put("password", "Please enter password");
}
if (messages.isEmpty()) {
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user);
response.sendRedirect(request.getContextPath() + "/home");
return;
} else {
messages.put("login", "Unknown login, please try again");
}
}
request.setAttribute("messages", messages);
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
}
}
See also:
Our servlet-filters wiki page
Our servlets wiki page
I have created a login page for mock of hotel administrator. Now I want to add session time function to it. In other words, let's say the user leaves the computer (he is still logged into the admin webpage) for like 10 minutes or so. Then when he come back, I want to end the current session and then redirect to login page (this is more secured and his personal info would never be lost!).
How do I make that happen?
public class LoginServlet extends SpringInjectedServlet {
#Autowired
private LoginService loginService;
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String id = req.getParameter("id");
String password = req.getParameter("password");
String error = null;
//code for checking correct input
}
// mock
private boolean check(String id, String password) {
return loginService.authenticate(id, password);
}
#Override
public void init() throws ServletException {
System.out.println("LoginServlet");
}
}
Use Authentication Filters to check for Session in every request like
HttpSession session = request.getSession();
if (session == null || session.getAttribute("username") == null) {
// Forward the control to login.jsp if authentication fails or session expires
request.getRequestDispatcher("/login.jsp").forward(request,
response);
}
This will check for login username from session for every request if its null or the session expired ,it will redirect to login page.
Add this in web.xml
<session-config>
<session-timeout>5</session-timeout>
</session-config>
Check it here.
After you've verified the credentials, set a session variable for the userid, and to set the session expiration:
session.setMaxInactiveInterval(600); //600 secs = 10 mins
session.setAttribute("userid", userid);
Then at the top of all your JSPs and in all your servlets you do something like:
String userid = (String)session.getAttribute("userid");
if(userid==null)
{
response.sendRedirect("login.jsp");
return; //the return is important; forces redirect to go now
}
After the 10 minutes have elapsed, this will only redirect the user to the login page if they click a link, refresh, or somehow go to another page. If they just leave the page sitting there open, it will still display. To change that you would have to involve Javascript somehow.
I need to do some checks before every page is loaded to see if there's a need to redirect the user to another page (for security reasons).
When I was using JSF 2.0 I used a phase listener to do this job. Now that I'm using JSF 2.2 and all my beans are not JSF beans anymore, but CDI beans, I think I'm offered better choices to do this (or not?).
I've heard of the viewAction event, but I wouldn't like to be repeating metadata on every page (only if there's no other option).
So what's the best approach to implement this scenario in JSF 2.2 with CDI?
UPDATE (after #skuntsel suggestion)
This is the filter that I'm using for now. I would like to use it only after authentication to simplify its code. By the way, if you can see any mistake in it, I would appreciate if you told me.
#WebFilter("/*")
public class SolicitacoesFilter implements Filter
{
// I can't just use #Inject private User _user, because it needs to be initialized
// only when the user is authenticated. Otherwise an exception is thrown. If this
// filter was called only after the authentication I could use the mentioned code.
private User _user;
#Inject
private Instance<User> _userGetter;
#Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
if (initializeUser(request))
{
if (_user.isProvisoryPassword())
{
// Redirect to another page...
return;
}
if (_user.getStatus() != Status.ACTIVE)
{
// Redirect to another page...
return;
}
}
chain.doFilter(request, response);
}
#Override
public void destroy()
{
}
private boolean initializeUser(ServletRequest request)
{
boolean userAuthenticated = ((HttpServletRequest) request).getUserPrincipal() != null;
if (userAuthenticated)
{
if (_user == null)
{
_user = _userGetter.get();
}
}
else
{
_user = null;
}
return _user != null;
}
}
Ok, what are the purposes of your redirection need ?
If it's about checking session User for authentification purposes, use filter:
Let's assume there is login form at : http://www.domain.com/login.jsf.
Once the user fires connect button, we want to redirect him to http://www.domain.com/member/welcome.jsf, and avoid other people not to access the member/welcome.jsf domain, I mean all the pages which are in http://www.domain.com/member/....
Here a simple design:
#WebFilter("/member/*")
public class SecurityCheck implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
#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();
if (session == null || session.getAttribute("User") == null) {
response.sendRedirect(request.getContextPath() + "/index.xhtml"); // No logged-in user found, so redirect to login page.
} else {
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
#Override
public void destroy() {
// Cleanup global variables if necessary.
}
Other case, use:
<h:link></h:link>,or <h:commandLink></h:commandLink> // Checking in the managed Beans method
You can also xml file, for redirection.
I would like to track user's sessions. I am interested in getting the user logname, context he accessed and the time when he accessed a certain context.
I was thinking of using a class that implements HttpSessionListener (overriding sessionCreated(final HttpSessionEvent se) and sessionDestroyed(final HttpSessionEvent se)) but on these methods I don't get access to the request (from where I could pull the user's logname and context he accessed).
Any suggestions are welcome.
I think a servlet Filter is more suitable for what you want. I suggest to write a custom filter around all the urls you want to track.
In the doFilter() method you have access to the HttpServletRequest as needed. From the request object you can get HttpSession too.
Here is an example:
#WebFilter("/*")
public class TrackingFilter implements Filter {
private FilterConfig filterConfig;
#Override
public void init(FilterConfig config) throws ServletException {
this.filterConfig = config;
}
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession(false);
String loggedInUser = "Unregistered user";
//assuming you have a session attribute named user with the username
if(session != null && session.getAttribute("user") != null) {
loggedInUser = (String) session.getAttribute("user");
}
Date accessedDate = new Date();
filterConfig.getServletContext().log(
String.format("%s accessed context %s on %tF %tT",
loggedInUser, request.getRequestURI() ,
accessedDate, accessedDate)
);
chain.doFilter(req, res);
}
#Override
public void destroy() {
}
}
See also: JavaEE6 tutorial section about filters.
I was designated to implement a security requierement to mimic "messenger like" authentication, for example: if a user first logs in, then another user tries to log in with the same username, this new user will be prompted to "kick" the previously loged user and the system should invalidate the first user's web session, the web app is running on tomcat 6, i was taking a look at HTTPSessionContext but its now deprecated, is there an alternative or should i go and implement something myself using a HTTPSessionListener ?
HTTPSessionListener might not work because you don't have access to the user principal there. I have done something similar using a filter (without the invalidation of the session). This is a striped down version of what I did with some code that might work for your situation (haven't tested it):
public class ApplicationFilter implements Filter {
private Map<String, HttpSession> sessions = new HashMap<String, HttpSession>();
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
Principal principal = request.getUserPrincipal();
HttpSession session = request.getSession();
if (principal != null && session.getAttribute("THE_PRINCIPAL") == null) {
// update the current session
session.setAttribute("THE_PRINCIPAL", session);
// get the username from the principal
// (assumes you using container based authentication)
String username = principal.getName();
// invalidate previous session if it exists
HttpSession s = sessions.get(username);
if (s != null)
s.invalidate();
// register this session as the one for the user
sessions.put(username, session);
}
chain.doFilter(servletRequest, servletResponse);
}
}