/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.utils; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import nl.strohalm.cyclos.access.MemberPermission; import nl.strohalm.cyclos.entities.access.Channel; import nl.strohalm.cyclos.entities.access.Channel.Principal; import nl.strohalm.cyclos.entities.access.MemberUser; import nl.strohalm.cyclos.entities.access.OperatorUser; import nl.strohalm.cyclos.entities.access.PrincipalType; import nl.strohalm.cyclos.entities.access.User; import nl.strohalm.cyclos.entities.accounts.Account; import nl.strohalm.cyclos.entities.accounts.guarantees.GuaranteeType; import nl.strohalm.cyclos.entities.accounts.loans.LoanGroupQuery; import nl.strohalm.cyclos.entities.accounts.pos.MemberPos; import nl.strohalm.cyclos.entities.customization.documents.Document; import nl.strohalm.cyclos.entities.customization.documents.DocumentQuery; import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException; import nl.strohalm.cyclos.entities.groups.AdminGroup; import nl.strohalm.cyclos.entities.groups.BrokerGroup; import nl.strohalm.cyclos.entities.groups.Group; import nl.strohalm.cyclos.entities.groups.MemberGroup; import nl.strohalm.cyclos.entities.groups.OperatorGroup; import nl.strohalm.cyclos.entities.members.Element; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.entities.members.Reference.Nature; import nl.strohalm.cyclos.entities.members.records.MemberRecordType; import nl.strohalm.cyclos.entities.members.records.MemberRecordTypeQuery; import nl.strohalm.cyclos.entities.settings.AccessSettings; import nl.strohalm.cyclos.exceptions.AccessDeniedException; import nl.strohalm.cyclos.exceptions.LoggedOutException; import nl.strohalm.cyclos.services.access.AccessService; import nl.strohalm.cyclos.services.access.ChannelService; import nl.strohalm.cyclos.services.access.exceptions.LoginException; import nl.strohalm.cyclos.services.access.exceptions.NotConnectedException; import nl.strohalm.cyclos.services.accounts.AccountService; import nl.strohalm.cyclos.services.accounts.guarantees.GuaranteeService; import nl.strohalm.cyclos.services.customization.DocumentService; import nl.strohalm.cyclos.services.elements.CommissionService; import nl.strohalm.cyclos.services.elements.ElementService; import nl.strohalm.cyclos.services.elements.MemberRecordTypeService; import nl.strohalm.cyclos.services.elements.ReferenceService; import nl.strohalm.cyclos.services.groups.GroupService; import nl.strohalm.cyclos.services.loangroups.LoanGroupService; import nl.strohalm.cyclos.services.permissions.PermissionService; import nl.strohalm.cyclos.services.preferences.ReceiptPrinterSettingsService; import nl.strohalm.cyclos.services.settings.SettingsService; import nl.strohalm.cyclos.utils.conversion.IdConverter; import nl.strohalm.cyclos.utils.query.PageHelper; import org.apache.commons.lang.StringUtils; /** * Helper class for login * @author luis */ public class LoginHelper { /** * Returns the currently logged user, or null if none */ public static User getLoggedUser(final HttpServletRequest request) { return (User) request.getAttribute("loggedUser"); } private ChannelService channelService; private ElementService elementService; private AccessService accessService; private GroupService groupService; private AccountService accountService; private PermissionService permissionService; private DocumentService documentService; private LoanGroupService loanGroupService; private ReferenceService referenceService; private MemberRecordTypeService memberRecordTypeService; private GuaranteeService guaranteeService; private SettingsService settingsService; private CommissionService commissionService; private ReceiptPrinterSettingsService receiptPrinterSettingsService; private boolean newSessionAfterLogin; /** * Perform the login itself */ public User login(final Class<? extends User> requiredUserClass, final String principalTypeString, final String memberUsername, final String principal, final String password, final String channel, final HttpServletRequest request, final HttpServletResponse response) throws LoginException { final String remoteAddress = request.getRemoteAddr(); final PrincipalType principalType = channelService.resolvePrincipalType(channel, principalTypeString); // Validate the user String usernameToVerify = principal; if (principalType.getPrincipal() != Principal.USER) { try { Member member; member = elementService.loadByPrincipal(principalType, principal, Element.Relationships.USER, Element.Relationships.GROUP); usernameToVerify = member.getUsername(); } catch (final EntityNotFoundException e) { usernameToVerify = ""; } } final User user = accessService.verifyLogin(memberUsername, usernameToVerify, remoteAddress); if (!requiredUserClass.isInstance(user)) { throw new AccessDeniedException(); } // Find the user nature final Group group = user.getElement().getGroup(); final boolean isAdmin = group instanceof AdminGroup; final boolean isMember = group instanceof MemberGroup; final boolean isBroker = group instanceof BrokerGroup; final boolean isOperator = group instanceof OperatorGroup; final boolean isPosWeb = RequestHelper.isPosWeb(request); final AccessSettings accessSettings = settingsService.getAccessSettings(); // Check if the administrator is allowed to login if (isAdmin && !accessSettings.getAdministrationWhitelistValidator().isAllowed(request.getRemoteHost(), request.getRemoteAddr())) { throw new AccessDeniedException(); } // According to the cyclos.properties flag, create a new session or use the current one HttpSession session; if (newSessionAfterLogin) { session = createNewSessionForlogin(request); } else { session = request.getSession(); } // Login the user accessService.login(user, password, channel, isPosWeb, remoteAddress, session.getId()); // Apply the session timeout final TimePeriod timeout = isPosWeb ? accessSettings.getPoswebTimeout() : isMember ? accessSettings.getMemberTimeout() : accessSettings.getAdminTimeout(); int timeoutSeconds = (int) timeout.getValueIn(TimePeriod.Field.SECONDS); if (timeoutSeconds <= 0) { timeoutSeconds = -1; } session.setMaxInactiveInterval(timeoutSeconds); // If is a member, determine if the member has accounts, documents, loan groups and memberPos boolean hasAccounts = false; boolean singleAccount = false; boolean hasDocuments = false; boolean hasLoanGroups = false; boolean hasGeneralReferences = false; boolean hasTransactionFeedbacks = false; boolean hasPin = false; boolean hasExternalChannels = false; boolean hasCards = false; boolean hasPos = false; boolean hasCommissionContracts = false; if (isMember || isOperator) { Member member; if (isMember) { member = ((MemberUser) user).getMember(); // Get the accessible channels final MemberGroup memberGroup = groupService.load(member.getMemberGroup().getId(), MemberGroup.Relationships.CHANNELS); hasPin = groupService.usesPin(memberGroup); for (final Channel current : memberGroup.getChannels()) { if (!Channel.WEB.equals(current.getInternalName())) { hasExternalChannels = true; break; } } if (!member.getPosDevices().isEmpty()) { hasPos = true; if (member.getPosDevices().size() == 1) { final Collection<MemberPos> memberPos = member.getPosDevices(); for (final MemberPos mpos : memberPos) { session.setAttribute("uniqueMemberPosId ", mpos.getPos().getId()); } } } } else { member = ((OperatorUser) user).getOperator().getMember(); } // Fetch broker member = elementService.load(member.getId(), Member.Relationships.BROKER); final MemberGroup memberGroup = member.getMemberGroup(); // Check if the member has accounts final List<? extends Account> accounts = accountService.getAccounts(member); hasAccounts = !accounts.isEmpty(); singleAccount = accounts.size() == 1; if (isMember) { // Check if the member has documents if (permissionService.hasPermission(MemberPermission.DOCUMENTS_VIEW)) { hasDocuments = true; } else { final DocumentQuery documentQuery = new DocumentQuery(); documentQuery.setNatures(Collections.singleton(Document.Nature.MEMBER)); documentQuery.setMember(member); documentQuery.setPageForCount(); hasDocuments = PageHelper.hasResults(documentService.search(documentQuery)); } // Check if the member has loan groups final LoanGroupQuery lgq = new LoanGroupQuery(); lgq.setPageForCount(); lgq.setMember(member); hasLoanGroups = PageHelper.hasResults(loanGroupService.search(lgq)); // Check if the member has commission contracts hasCommissionContracts = commissionService.hasBrokerCommissionContracts(); } // Check if the user has references final Collection<Nature> referenceNatures = referenceService.getNaturesByGroup(memberGroup); hasGeneralReferences = referenceNatures.contains(Nature.GENERAL); hasTransactionFeedbacks = referenceNatures.contains(Nature.TRANSACTION); // Check if the user can have guarantees try { final Collection<GuaranteeType.Model> guaranteeModels = guaranteeService.getRelatedGuaranteeModels(); session.setAttribute("loggedMemberHasGuarantees", guaranteeModels.size() > 0); } catch (final Exception e) { // Ignore } // Check if the user has cards hasCards = member.getCards().isEmpty() ? false : true; } if (isAdmin || isBroker) { // Retrieve the member record types the logged user can see on the menu final MemberRecordTypeQuery query = new MemberRecordTypeQuery(); if (isAdmin) { query.setViewableByAdminGroup((AdminGroup) group); } else { query.setViewableByBrokerGroup((BrokerGroup) group); } query.setShowMenuItem(true); final List<MemberRecordType> types = memberRecordTypeService.search(query); session.setAttribute("memberRecordTypesInMenu", types); } // When a receipt printer cookie is set, and the printer no longer exists, or belongs to someone else, clear the cookie final String receiptPrinterId = RequestHelper.getCookieValue(request, "receiptPrinterId"); if (StringUtils.isNotEmpty(receiptPrinterId)) { final Long id = IdConverter.instance().valueOf(receiptPrinterId); if (!receiptPrinterSettingsService.belongsToTheLoggedUser(id)) { final Cookie cookie = new Cookie("receiptPrinterId", ""); cookie.setPath(request.getContextPath()); response.addCookie(cookie); } } final String actionPrefix = "/" + (isAdmin ? "admin" : isMember ? "member" : "operator"); // Set the request attributes request.setAttribute("loggedUser", user); request.setAttribute("loggedElement", user.getElement()); // Set the session attributes session.setAttribute("loggedUserId", user.getId()); session.setAttribute("isAdmin", isAdmin); session.setAttribute("isMember", isMember); session.setAttribute("isBroker", isBroker); session.setAttribute("isOperator", isOperator); session.setAttribute("isBuyer", guaranteeService.isBuyer()); session.setAttribute("isSeller", guaranteeService.isSeller()); session.setAttribute("isIssuer", guaranteeService.isIssuer()); session.setAttribute("loggedMemberHasAccounts", hasAccounts); session.setAttribute("loggedMemberHasSingleAccount", singleAccount); session.setAttribute("loggedMemberHasDocuments", hasDocuments); session.setAttribute("loggedMemberHasLoanGroups", hasLoanGroups); session.setAttribute("loggedMemberHasGeneralReferences", hasGeneralReferences); session.setAttribute("loggedMemberHasTransactionFeedbacks", hasTransactionFeedbacks); session.setAttribute("hasPin", hasPin); session.setAttribute("hasCards", hasCards); session.setAttribute("hasPos", hasPos); session.setAttribute("hasCommissionContracts", hasCommissionContracts); session.setAttribute("hasExternalChannels", hasExternalChannels); session.setAttribute("actionPrefix", actionPrefix); session.setAttribute("pathPrefix", "/do" + actionPrefix); session.setAttribute("navigation", Navigation.get(session)); // Return the logged user return user; } public void setAccessService(final AccessService accessService) { this.accessService = accessService; } public void setAccountService(final AccountService accountService) { this.accountService = accountService; } public void setChannelService(final ChannelService channelService) { this.channelService = channelService; } public void setCommissionService(final CommissionService commissionService) { this.commissionService = commissionService; } public void setCyclosProperties(final Properties cyclosProperties) { newSessionAfterLogin = Boolean.parseBoolean(cyclosProperties.getProperty("cyclos.newSessionAfterLogin", "true")); } public void setDocumentService(final DocumentService documentService) { this.documentService = documentService; } public void setElementService(final ElementService elementService) { this.elementService = elementService; } public void setGroupService(final GroupService groupService) { this.groupService = groupService; } public void setGuaranteeService(final GuaranteeService guaranteeService) { this.guaranteeService = guaranteeService; } public void setLoanGroupService(final LoanGroupService loanGroupService) { this.loanGroupService = loanGroupService; } public void setMemberRecordTypeService(final MemberRecordTypeService memberRecordTypeService) { this.memberRecordTypeService = memberRecordTypeService; } public void setPermissionService(final PermissionService permissionService) { this.permissionService = permissionService; } public void setReceiptPrinterSettingsService(final ReceiptPrinterSettingsService receiptPrinterSettingsService) { this.receiptPrinterSettingsService = receiptPrinterSettingsService; } public void setReferenceService(final ReferenceService referenceService) { this.referenceService = referenceService; } public void setSettingsService(final SettingsService settingsService) { this.settingsService = settingsService; } /** * Returns the currently logged user, ensuring there is one */ public User validateLoggedUser(final HttpServletRequest request) { final HttpSession session = request.getSession(); // Find the logged user final User user = getLoggedUser(request); if (user == null) { throw new LoggedOutException(); } // Find the registered logged user for the session id User serviceUser; try { serviceUser = accessService.getLoggedUser(session.getId()); } catch (final NotConnectedException e) { throw new LoggedOutException(); } // The web container session indicates there is an user, but there's no tracked session: invalidate the session's user if (user != null && serviceUser == null) { session.removeAttribute("loggedUser"); throw new LoggedOutException(); } else { // Ensure they match final boolean valid = user != null && user.equals(serviceUser); if (!valid) { session.invalidate(); throw new AccessDeniedException(); } } return user; } @SuppressWarnings("rawtypes") private HttpSession createNewSessionForlogin(final HttpServletRequest request) { HttpSession session = request.getSession(); // retrieve the current attributes final Map<String, Object> attrMap = new HashMap<String, Object>(); for (final Enumeration e = session.getAttributeNames(); e.hasMoreElements();) { final String attrName = (String) e.nextElement(); attrMap.put(attrName, session.getAttribute(attrName)); } // invalidates and creates a new session session.invalidate(); session = request.getSession(); // copy the previous attributes to the new session for (final Map.Entry<String, Object> entry : attrMap.entrySet()) { session.setAttribute(entry.getKey(), entry.getValue()); } return session; } }