Commit 22ce9853 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

minerva session id is provided as a spring security session id and is stored via spring

parent 1fa1f24e
package lcsb.mapviewer.api.users;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -13,8 +12,12 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.CookieValue;
......@@ -50,34 +53,36 @@ public class UserController extends BaseController {
@Autowired
private UserRestImpl userRest;
@Autowired
private AuthenticationProvider authenticationProvider;
@Autowired
private SessionRegistry sessionRegistry;
@RequestMapping(value = "/doLogin", method = { RequestMethod.GET, RequestMethod.POST }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public Map<String, Object> login(//
@RequestParam(value = "login", defaultValue = Configuration.ANONYMOUS_LOGIN) String login, //
@RequestParam(value = "password", required = false) String password, //
HttpServletResponse response //
@RequestParam(value = "password", defaultValue = "") String password, //
HttpServletResponse response, //
HttpServletRequest request//
) throws SecurityException, IOException {
AuthenticationToken token = userService.login(login, password);
AuthenticationToken token = userService.login(login, password, request.getSession().getId());
if (token == null) {
throw new SecurityException("Invalid credentials");
} else {
UsernamePasswordAuthenticationToken springToken = new UsernamePasswordAuthenticationToken(login, password);
springToken.setDetails(new WebAuthenticationDetails(request));
Authentication authentication = this.authenticationProvider.authenticate(springToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
sessionRegistry.registerNewSession(request.getSession().getId(), authentication.getPrincipal());
Map<String, Object> result = new HashMap<>();
final Boolean useSecureCookie = false;
final int expiryTime = (int) (token.getExpires().getTimeInMillis() - Calendar.getInstance().getTimeInMillis())
/ 1000;
final String cookiePath = "/";
Cookie cookie = new Cookie("MINERVA_AUTH_TOKEN", token.getId());
cookie.setSecure(useSecureCookie);
cookie.setMaxAge(expiryTime);
cookie.setPath(cookiePath);
response.addCookie(cookie);
result.put("info", "Login successful. TOKEN returned as a cookie");
return result;
}
}
result.put("info", "Login successful. TOKEN returned as a cookie");
return result;
}
}
@RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.GET }, produces = {
MediaType.APPLICATION_JSON_VALUE })
......@@ -126,15 +131,13 @@ public class UserController extends BaseController {
public Map<String, String> logout(@CookieValue(value = Configuration.AUTH_TOKEN) String token,
HttpServletRequest request, HttpServletResponse response //
) throws SecurityException, IOException {
//spring logout
// spring logout
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
logger.debug("LOGOUT");
logger.debug(auth);
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
if (auth != null) {
new SecurityContextLogoutHandler().logout(request, response, auth);
}
//our session manager logout
userService.logout(token);
Map<String, String> result = new HashMap<>();
result.put("status", "OK");
......@@ -148,24 +151,26 @@ public class UserController extends BaseController {
cookie.setMaxAge(0);
cookie.setPath(cookiePath);
response.addCookie(cookie);
result.put("status", "OK");
return result;
}
response.addCookie(cookie);
result.put("status", "OK");
return result;
}
@RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.PATCH }, produces = { MediaType.APPLICATION_JSON_VALUE })
@RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.PATCH }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public Map<String, Object> updateUser(//
@RequestBody String body, //
@PathVariable(value = "login") String login, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
@RequestBody String body, //
@PathVariable(value = "login") String login, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
) throws SecurityException, QueryException, IOException {
Map<String, Object> node = parseBody(body);
Map<String, Object> data = getData(node, "user");
return userRest.updateUser(token, login, data);
Map<String, Object> node = parseBody(body);
Map<String, Object> data = getData(node, "user");
return userRest.updateUser(token, login, data);
}
@RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE })
public Map<String, Object> addOverlay(//
@RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.POST }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public Map<String, Object> addOverlay(//
@RequestBody MultiValueMap<String, Object> formData, //
@PathVariable(value = "login") String login, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
......@@ -174,7 +179,8 @@ public class UserController extends BaseController {
}
@RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.DELETE }, produces = { MediaType.APPLICATION_JSON_VALUE })
@RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.DELETE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public Map<String, Object> removeProject(//
@PathVariable(value = "login") String login, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
......@@ -183,7 +189,6 @@ public class UserController extends BaseController {
}
/**
* @return the userService
* @see #userService
......
package lcsb.mapviewer.services.impl;
import java.awt.Color;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
......@@ -78,6 +83,9 @@ public class UserService implements IUserService {
@Autowired
private PrivilegeDao privilegeDao;
@Autowired
private SessionRegistry sessionRegistry;
/**
* Factory object for {@link UserView} elements.
*/
......@@ -97,42 +105,23 @@ public class UserService implements IUserService {
private ILogService logService;
/**
* Service used for accessing confguration parameters.
* Service used for accessing configuration parameters.
*/
@Autowired
private IConfigurationService configurationService;
@Override
public AuthenticationToken login(String login, String password) {
User user = userDao.getUserByLoginAndPassword(login, password);
if (Configuration.ANONYMOUS_LOGIN.equals(login)) {
user = getUserByLogin(Configuration.ANONYMOUS_LOGIN);
}
if (user != null) {
int count = 0;
synchronized (authenticationTokens) {
count = authenticationTokens.size();
}
if (count > 1000) {
clearAuthenticationTokens();
}
AuthenticationToken authenticationToken = new AuthenticationToken();
synchronized (authenticationTokens) {
authenticationTokens.put(authenticationToken.getId(), authenticationToken);
authenticatedUsers.put(authenticationToken, user);
}
return authenticationToken;
} else {
return null;
}
Random random = new SecureRandom();
String id = new BigInteger(130, random).toString(32);
return this.login(login, password, id);
}
private void clearAuthenticationTokens() {
synchronized (authenticationTokens) {
List<String> toRemove = new ArrayList<>();
for (AuthenticationToken token : authenticationTokens.values()) {
if (token.getExpires().before(Calendar.getInstance())) {
if (isSessionExpired(token)) {
toRemove.add(token.getId());
}
}
......@@ -522,7 +511,7 @@ public class UserService implements IUserService {
@Override
public User getUserByToken(AuthenticationToken token) {
User result = null;
if (Calendar.getInstance().before(token.getExpires())) {
if (!isSessionExpired(token)) {
synchronized (authenticationTokens) {
result = authenticatedUsers.get(token);
}
......@@ -544,13 +533,22 @@ public class UserService implements IUserService {
if (result == null) {
throw new InvalidTokenException("Token string is invalid");
}
if (result.getExpires().before(Calendar.getInstance())) {
if (isSessionExpired(result)) {
logout(result);
throw new AuthenticationTokenExpireException("Token validity expired");
}
return result;
}
private boolean isSessionExpired(AuthenticationToken result) {
SessionInformation sessionData = sessionRegistry.getSessionInformation(result.getId());
if (sessionData == null) {
logger.debug("No session data for token id: " + result.getId());
return true;
}
return sessionData.isExpired();
}
@Override
public void logout(AuthenticationToken token) {
synchronized (authenticationTokens) {
......@@ -664,4 +662,30 @@ public class UserService implements IUserService {
return userHasPrivilege(getUserByToken(token), type);
}
@Override
public AuthenticationToken login(String login, String password, String id) {
User user = userDao.getUserByLoginAndPassword(login, password);
if (user == null && Configuration.ANONYMOUS_LOGIN.equals(login) && "".equals(password)) {
user = getUserByLogin(Configuration.ANONYMOUS_LOGIN);
}
if (user != null) {
int count = 0;
synchronized (authenticationTokens) {
count = authenticationTokens.size();
}
if (count > 1000) {
clearAuthenticationTokens();
}
AuthenticationToken authenticationToken = new AuthenticationToken(id);
synchronized (authenticationTokens) {
authenticationTokens.put(authenticationToken.getId(), authenticationToken);
authenticatedUsers.put(authenticationToken, user);
}
return authenticationToken;
} else {
return null;
}
}
}
......@@ -15,256 +15,258 @@ import lcsb.mapviewer.services.view.UserView;
* Service that manages users.
*
* @author Piotr Gawron
*
*
*/
public interface IUserService {
/**
* Check if its possible to login using given login and password.
*
* @param login
* user login
* @param password
* plan password
* @return {@link AuthenticationToken} if credentials are valid,
* <code>null</code> otherwise
*/
AuthenticationToken login(String login, String password);
/**
* Returns user by login.
*
* @param login
* user login
* @return user if the login is valid, <code>null</code> otherwise
*/
User getUserByLogin(String login);
/**
* Checks if user has a given privilege.
*
* @param user
* user for which the check is performed
* @param type
* type of the privilege
* @return <code>true</code> if user has privilege, <code>false</code>
* otherwise
*/
boolean userHasPrivilege(User user, PrivilegeType type);
boolean userHasPrivilege(String token, PrivilegeType type) throws SecurityException;
/**
* Returns level of the user privilege.
*
* @param user
* user for which the check is performed
* @param type
* type of the privilege
* @return level of the privilege
*/
int getUserPrivilegeLevel(User user, PrivilegeType type);
/**
* Checks if user has a given privilege on the object.
*
* @param user
* user for which the check is performed
* @param type
* type of the privilege
* @param object
* object of the privilege
* @return <code>true</code> if user has privilege, <code>false</code>
* otherwise
*/
boolean userHasPrivilege(User user, PrivilegeType type, Object object);
/**
* Returns level of the user privilege.
*
* @param object
* object of the privilege
* @param user
* user for which the check is performed
* @param type
* type of the privilege
* @return level of the privilege
*/
int getUserPrivilegeLevel(User user, PrivilegeType type, Object object);
/**
* Sets the user privilege.
*
* @param user
* user for whom the privilege should be granted/dropped
* @param privilege
* user privilege
*/
void setUserPrivilege(User user, BasicPrivilege privilege);
/**
* Adds user to the system.
*
* @param user
* user to be added
*/
void addUser(User user);
/**
* Updates user in the system.
*
* @param user
* user to be updated
*/
void updateUser(User user);
/**
* Removes user from the system.
*
* @param user
* user to be removed
*/
void deleteUser(User user);
/**
* Returns user by the database identifier.
*
* @param id
* database identifier
* @return user for the given identifier, null if user doesn't exist
*
*/
User getUserById(int id);
/**
* Returns user views for all users.
*
* @return list of user {@link lcsb.mapviewer.services.view.AbstractView
* views} for all users
*/
List<UserView> getAllUserRows();
/**
* @param user
* user that will have view.
* @return view for one user.
*/
UserView getUserRow(User user);
/**
* Updates user from user {@link lcsb.mapviewer.services.view.AbstractView
* view}.
*
* @param selectedUser
* user {@link lcsb.mapviewer.services.view.AbstractView view} to
* update
*/
void updateUser(UserView selectedUser);
/**
* Removes user based on user {@link lcsb.mapviewer.services.view.AbstractView
* view}.
*
* @param selectedUser
* user {@link lcsb.mapviewer.services.view.AbstractView view} to be
* removed
*/
void deleteUser(UserView selectedUser);
/**
* Creates empty view.
*
* @return empty user {@link lcsb.mapviewer.services.view.AbstractView view} .
*/
UserView createEmptyUserRow();
/**
* Drops privileges for every user on the given object and type.
*
* @param type
* type of privilege that should be dropped
* @param objectId
* identifier of the object to which privileges should be dropped
*/
void dropPrivilegesForObjectType(PrivilegeType type, int objectId);
/**
* Adds user from user view.
*
* @param selectedUser
* user view representation that should be added
*/
void addUser(UserView selectedUser);
/**
* Adds privilege to the user.
*
* @param user
* user to which privilege should be added
* @param type
* type of the privilege
*/
void setUserPrivilege(User user, PrivilegeType type, Integer value);
/**
* Updates users from list of user
* {@link lcsb.mapviewer.services.view.AbstractView view}.
*
* @param users
* user {@link lcsb.mapviewer.services.view.AbstractView views} to
* update
*/
void updateUsers(Collection<UserView> users);
/**
* @param password
* input password
* @return encoded password
*/
String encodePassword(String password);
/**
* Returns {@link User} for given "name surname" string.
*
* @param nameSurnameString
* string identifying user with name and surname separated by single
* space
* @return {@link User} for given "name surname" string
*/
User getUserByNameSurname(String nameSurnameString);
/**
* Returns {@link ColorExtractor} that transform overlay values into colors
* for given user.
*
* @param user
* {@link User} for which {@link ColorExtractor} will be obtained
* @return {@link ColorExtractor} that transform overlay values into colors
* for given user
*/
ColorExtractor getColorExtractorForUser(User user);
User getUserByToken(AuthenticationToken token);
User getUserByToken(String token) throws SecurityException;
AuthenticationToken getToken(String token) throws SecurityException;
boolean userHasPrivilege(AuthenticationToken token, PrivilegeType type, Object object);
void logout(String tokenString) throws SecurityException;
void logout(AuthenticationToken token);
boolean userHasPrivilege(AuthenticationToken token, PrivilegeType addMap);
User getUserById(String creatorId, AuthenticationToken authenticationToken) throws SecurityException;
List<User> getUsers(AuthenticationToken token) throws SecurityException;
void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, AuthenticationToken authenticationToken) throws SecurityException;
void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, Integer objectId, AuthenticationToken authenticationToken) throws SecurityException;
void updateUser(User modifiedUser, AuthenticationToken authenticationToken) throws SecurityException;
/**
* Check if its possible to login using given login and password.
*
* @param login
* user login
* @param password
* plan password
* @return {@link AuthenticationToken} if credentials are valid,
* <code>null</code> otherwise
*/
AuthenticationToken login(String login, String password);
/**
* Returns user by login.
*
* @param login
* user login
* @return user if the login is valid, <code>null</code> otherwise
*/
User getUserByLogin(String login);
/**
* Checks if user has a given privilege.
*
* @param user
* user for which the check is performed
* @param type
* type of the privilege
* @return <code>true</code> if user has privilege, <code>false</code> otherwise
*/
boolean userHasPrivilege(User user, PrivilegeType type);
boolean userHasPrivilege(String token, PrivilegeType type) throws SecurityException;
/**
* Returns level of the user privilege.
*
* @param user
* user for which the check is performed
* @param type
* type of the privilege