001/** 002 * Copyright 2014 Tampere University of Technology, Pori Department 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package core.tut.pori.context; 017 018import java.io.IOException; 019 020import javax.servlet.ServletException; 021import javax.servlet.http.HttpServlet; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024import javax.servlet.http.HttpSession; 025 026import org.apache.log4j.Logger; 027import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 028import org.springframework.security.core.Authentication; 029import org.springframework.security.core.context.SecurityContextHolder; 030 031import service.tut.pori.users.UserCore; 032import core.tut.pori.http.Response; 033import core.tut.pori.http.Response.Status; 034import core.tut.pori.users.UserIdentity; 035 036/** 037 * This class handles to basic login/logout functionality and session creation/destruction. 038 * 039 * This class defines the APIs available for client authentication. Note that it is also possible to authenticate by IP address without username or password check, but the functionality must be enabled per IP basis using the front-end system configuration, and is in general recommended only for analysis back-ends. The IP authentication configuration is out of scope for this documentation. 040 * The user authorization is done by checking the presence and validity of a session ID in the header list (cookie) of the executed HTTP request. The session ID can be generated by any of the login methods documented in this specification. It is also possible to provide the authentication details, such as username and password for HTTP basic authentication, for each request, though this is not necessary. 041 * The default configuration prevents multiple logins, and re-authentication will automatically invalidate the previous session, creating a new a session and a new session ID. 042 * 043 * This class is generally bound using web.xml to be outside of REST handler, working independently from the service invocation functionality. 044 */ 045public class LoginHandler extends HttpServlet{ 046 private static final Logger LOGGER = Logger.getLogger(LoginHandler.class); 047 private static final String METHOD_LOGIN = "login"; 048 /** serialization id */ 049 private static final long serialVersionUID = 956966155730567889L; 050 051 @Override 052 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 053 handleRequest(req, resp); 054 } 055 056 @Override 057 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 058 handleRequest(req, resp); 059 } 060 061 /** 062 * 063 * @param request 064 * @param response 065 */ 066 private void handleRequest(HttpServletRequest request, HttpServletResponse response){ 067 if(request.getRequestURI().endsWith(METHOD_LOGIN)){ 068 login(getAuthentication(), request, response); 069 }else{ // ther are only two mappings in the web.xml, if this is not login, it must be logout 070 logout(getAuthentication(), request, response); 071 } 072 } 073 074 /** 075 * Login the user using HTTP Basic authentication. Successful authentication attempt will return a new session ID (as a response cookie) that can be used for further authentication. 076 * 077 * @param auth 078 * @param request 079 * @param response 080 */ 081 private void login(Authentication auth, HttpServletRequest request, HttpServletResponse response){ 082 LOGGER.debug("Received login request "+request.getMethod()+" from "+request.getRemoteAddr()); 083 if(auth == null){ 084 new Response(Status.UNAUTHORIZED).writeTo(response); 085 return; 086 } 087 new Response().writeTo(response); 088 } 089 090 /** 091 * Log out the user. This will invalidate the session Id (cookie) currently used by the user. Note that in many cases the only noticeable effect of calling this method is to invalidate the session Id, as most web browsers will automatically re-authenticate the user on any following calls if user credentials are known, thus creating a new session. 092 * 093 * @param auth 094 * @param request 095 * @param response 096 */ 097 private void logout(Authentication auth, HttpServletRequest request, HttpServletResponse response){ 098 LOGGER.debug("Received logout request "+request.getMethod()+" from "+request.getRemoteAddr()); 099 if(auth == null){ 100 LOGGER.debug("User was not logged in."); 101 new Response().writeTo(response); 102 return; 103 } 104 auth.setAuthenticated(false); 105 HttpSession session = request.getSession(false); 106 if(session == null){ 107 LOGGER.debug("No valid session."); 108 }else{ 109 LOGGER.debug("Invalidating session."); 110 session.invalidate(); 111 } 112 113 SecurityContextHolder.clearContext(); 114 new Response().writeTo(response); 115 } 116 117 /** 118 * 119 * @return authentication or null if user has not authenticated 120 */ 121 private Authentication getAuthentication(){ 122 Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 123 if(auth != null && auth.isAuthenticated()){ 124 Object principal = auth.getPrincipal(); 125 if(principal.getClass() == UserIdentity.class){ 126 return auth; 127 }else{ 128 LOGGER.debug("UserDetails not available."); 129 } 130 } 131 return null; 132 } 133 134 /** 135 * Set this user as authenticated for the current security context 136 * 137 * @param userId 138 * @throws IllegalArgumentException on bad userId 139 */ 140 public static void authenticate(UserIdentity userId) throws IllegalArgumentException{ 141 userId = UserCore.getUserIdentity(userId.getUserId()); // retrieve all details 142 if(!UserIdentity.isValid(userId)){ 143 throw new IllegalArgumentException("Bad user, id: "+userId.getUserId()); 144 } 145 SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userId, userId.getPassword(), userId.getAuthorities())); 146 } 147}