Java tutorial
/* * Copyright (c) 2008-2016 Haulmont. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.haulmont.cuba.security.app; import com.haulmont.cuba.core.*; import com.haulmont.cuba.core.app.ClusterManagerAPI; import com.haulmont.cuba.core.app.ServerConfig; import com.haulmont.cuba.core.global.*; import com.haulmont.cuba.core.sys.AppContext; import com.haulmont.cuba.core.sys.remoting.RemoteClientInfo; import com.haulmont.cuba.security.entity.RememberMeToken; import com.haulmont.cuba.security.entity.User; import com.haulmont.cuba.security.global.LoginException; import com.haulmont.cuba.security.global.NoUserSessionException; import com.haulmont.cuba.security.global.UserSession; import com.haulmont.cuba.security.sys.TrustedLoginHandler; import com.haulmont.cuba.security.sys.UserSessionManager; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.annotation.Nullable; import javax.inject.Inject; import java.util.*; /** * Class that encapsulates the middleware login/logout functionality. * * @see com.haulmont.cuba.security.app.LoginServiceBean */ @Component(LoginWorker.NAME) public class LoginWorkerBean implements LoginWorker { private Logger log = LoggerFactory.getLogger(LoginWorkerBean.class); protected static final String MSG_PACK = "com.haulmont.cuba.security"; @Inject protected Persistence persistence; @Inject protected Messages messages; protected Configuration configuration; @Inject protected PasswordEncryption passwordEncryption; @Inject protected UserSessionManager userSessionManager; @Inject protected UserSessionSource userSessionSource; @Inject protected TrustedLoginHandler trustedLoginHandler; @Inject protected ClusterManagerAPI clusterManager; @Inject protected Authentication authentication; @Inject public void setConfiguration(Configuration configuration) { this.configuration = configuration; } @Nullable protected User loadUser(String login) throws LoginException { if (login == null) throw new IllegalArgumentException("Login is null"); EntityManager em = persistence.getEntityManager(); String queryStr = "select u from sec$User u where u.loginLowerCase = ?1 and (u.active = true or u.active is null)"; Query q = em.createQuery(queryStr); q.setParameter(1, login.toLowerCase()); List list = q.getResultList(); if (list.isEmpty()) { log.warn("Failed to authenticate: " + login); return null; } else { //noinspection UnnecessaryLocalVariable User user = (User) list.get(0); return user; } } @Nullable protected RememberMeToken loadRememberMeToken(String rememberMeToken, User user) { EntityManager em = persistence.getEntityManager(); TypedQuery<RememberMeToken> query = em.createQuery( "select rt from sec$RememberMeToken rt where rt.token = :token and rt.user.id = :userId", RememberMeToken.class); query.setParameter("token", rememberMeToken); query.setParameter("userId", user.getId()); return query.getFirstResult(); } @Override public UserSession login(String login, String password, Locale locale) throws LoginException { return login(login, password, locale, Collections.emptyMap()); } @Override public UserSession login(String login, String password, Locale locale, Map<String, Object> params) throws LoginException { if (password == null) throw new LoginException(getInvalidCredentialsMessage(login, locale)); Transaction tx = persistence.createTransaction(); try { User user = loadUser(login); if (user == null) throw new LoginException(getInvalidCredentialsMessage(login, locale)); if (!passwordEncryption.checkPassword(user, password)) throw new LoginException(getInvalidCredentialsMessage(login, locale)); Locale userLocale = locale; if (user.getLanguage() != null && BooleanUtils.isFalse(configuration.getConfig(GlobalConfig.class).getLocaleSelectVisible())) { userLocale = new Locale(user.getLanguage()); } UserSession session = userSessionManager.createSession(user, userLocale, false); checkPermissions(login, params, userLocale, session); log.info("Logged in: " + session); tx.commit(); userSessionManager.clearPermissionsOnUser(session); Boolean sync = (Boolean) params.get(ServerConfig.SYNC_NEW_USER_SESSION_REPLICATION_PROP); if (sync != null && sync) { boolean saved = clusterManager.getSyncSendingForCurrentThread(); clusterManager.setSyncSendingForCurrentThread(true); try { userSessionManager.storeSession(session); } finally { clusterManager.setSyncSendingForCurrentThread(saved); } } else { userSessionManager.storeSession(session); } return session; } finally { tx.end(); } } protected String getInvalidCredentialsMessage(String login, Locale locale) { return messages.formatMessage(MSG_PACK, "LoginException.InvalidLoginOrPassword", locale, login); } @Override public UserSession loginSystem(String login) throws LoginException { Locale locale = messages.getTools().trimLocale(messages.getTools().getDefaultLocale()); Transaction tx = persistence.createTransaction(); try { User user = loadUser(login); if (user == null) throw new LoginException(getInvalidCredentialsMessage(login, locale)); UserSession session = userSessionManager.createSession(user, locale, true); log.info("Logged in: " + session); tx.commit(); userSessionManager.clearPermissionsOnUser(session); userSessionManager.storeSession(session); return session; } finally { tx.end(); } } @Override public UserSession getSystemSession(String trustedClientPassword) throws LoginException { RemoteClientInfo remoteClientInfo = RemoteClientInfo.get(); if (remoteClientInfo != null) { // reject request from not permitted client ip if (!trustedLoginHandler.checkAddress(remoteClientInfo.getAddress())) { log.warn("Attempt of trusted login from not permitted IP address: {}", remoteClientInfo.getAddress()); throw new LoginException(getInvalidCredentialsMessage(remoteClientInfo.getAddress(), messages.getTools().getDefaultLocale())); } } else { log.debug("Unable to check trusted client IP when obtaining system session"); } if (!trustedLoginHandler.checkPassword(trustedClientPassword)) { throw new LoginException(getInvalidCredentialsMessage(AppContext.getProperty("cuba.jmxUserLogin"), messages.getTools().getDefaultLocale())); } UserSession userSession = authentication.begin(); authentication.end(); return userSession; } @Override public UserSession loginTrusted(String login, String password, Locale locale) throws LoginException { return loginTrusted(login, password, locale, Collections.emptyMap()); } @Override public UserSession loginTrusted(String login, String password, Locale locale, Map<String, Object> params) throws LoginException { RemoteClientInfo remoteClientInfo = RemoteClientInfo.get(); if (remoteClientInfo != null) { // reject request from not permitted client ip if (!trustedLoginHandler.checkAddress(remoteClientInfo.getAddress())) { log.warn("Attempt of trusted login from not permitted IP address: {} {}", login, remoteClientInfo.getAddress()); throw new LoginException(getInvalidCredentialsMessage(login, locale)); } } else { log.debug("Unable to check trusted client IP when obtaining system session"); } if (!trustedLoginHandler.checkPassword(password)) throw new LoginException(getInvalidCredentialsMessage(login, locale)); Transaction tx = persistence.createTransaction(); try { User user = loadUser(login); if (user == null) { throw new LoginException( messages.formatMessage(MSG_PACK, "LoginException.InvalidUser", locale, login)); } Locale userLocale = locale; if (user.getLanguage() != null && BooleanUtils.isFalse(configuration.getConfig(GlobalConfig.class).getLocaleSelectVisible())) { userLocale = new Locale(user.getLanguage()); } UserSession session = userSessionManager.createSession(user, userLocale, false); checkPermissions(login, params, userLocale, session); log.info("Logged in: " + session); tx.commit(); userSessionManager.clearPermissionsOnUser(session); userSessionManager.storeSession(session); return session; } finally { tx.end(); } } @Override public UserSession loginByRememberMe(String login, String rememberMeToken, Locale locale) throws LoginException { return loginByRememberMe(login, rememberMeToken, locale, Collections.emptyMap()); } @Override public UserSession loginByRememberMe(String login, String rememberMeToken, Locale locale, Map<String, Object> params) throws LoginException { Transaction tx = persistence.createTransaction(); try { User user = loadUser(login); if (user == null) { throw new LoginException( messages.formatMessage(MSG_PACK, "LoginException.InvalidUser", locale, login)); } RememberMeToken loginToken = loadRememberMeToken(rememberMeToken, user); if (loginToken == null) { throw new LoginException(getInvalidCredentialsMessage(login, locale)); } Locale userLocale = locale; if (user.getLanguage() != null && BooleanUtils.isFalse(configuration.getConfig(GlobalConfig.class).getLocaleSelectVisible())) { userLocale = new Locale(user.getLanguage()); } UserSession session = userSessionManager.createSession(user, userLocale, false); checkPermissions(login, params, userLocale, session); log.info("Logged in: " + session); tx.commit(); userSessionManager.clearPermissionsOnUser(session); userSessionManager.storeSession(session); return session; } finally { tx.end(); } } @Override public void logout() { try { UserSession session = userSessionSource.getUserSession(); userSessionManager.removeSession(session); log.info("Logged out: " + session); } catch (SecurityException e) { log.warn("Couldn't logout: " + e); } catch (NoUserSessionException e) { log.warn("NoUserSessionException thrown on logout"); } } @Override public UserSession substituteUser(User substitutedUser) { UserSession currentSession = userSessionSource.getUserSession(); Transaction tx = persistence.createTransaction(); try { EntityManager em = persistence.getEntityManager(); User user; if (currentSession.getUser().equals(substitutedUser)) { user = em.find(User.class, substitutedUser.getId()); if (user == null) throw new javax.persistence.NoResultException("User not found"); } else { TypedQuery<User> query = em .createQuery("select s.substitutedUser from sec$User u join u.substitutions s " + "where u.id = ?1 and s.substitutedUser.id = ?2", User.class); query.setParameter(1, currentSession.getUser()); query.setParameter(2, substitutedUser); List<User> list = query.getResultList(); if (list.isEmpty()) throw new javax.persistence.NoResultException("User not found"); else user = list.get(0); } UserSession session = userSessionManager.createSession(currentSession, user); tx.commit(); userSessionManager.removeSession(currentSession); userSessionManager.clearPermissionsOnUser(session); userSessionManager.storeSession(session); return session; } finally { tx.end(); } } @Override public UserSession getSession(UUID sessionId) { try { //noinspection UnnecessaryLocalVariable UserSession session = userSessionManager.getSession(sessionId); return session; } catch (RuntimeException e) { if (e instanceof NoUserSessionException) return null; else throw e; } } @Override public boolean checkRememberMe(String login, String rememberMeToken) { boolean verified = false; Transaction tx = persistence.createTransaction(); try { EntityManager em = persistence.getEntityManager(); TypedQuery<RememberMeToken> query = em.createQuery( "select rt from sec$RememberMeToken rt where rt.token = :token and rt.user.loginLowerCase = :userLogin", RememberMeToken.class); query.setParameter("token", rememberMeToken); query.setParameter("userLogin", StringUtils.lowerCase(login)); if (query.getFirstResult() != null) { verified = true; } tx.commit(); } finally { tx.end(); } return verified; } protected void checkPermissions(String login, Map<String, Object> params, Locale userLocale, UserSession session) throws LoginException { String clientTypeParam = (String) params.get(ClientType.class.getName()); if (ClientType.DESKTOP.name().equals(clientTypeParam) || ClientType.WEB.name().equals(clientTypeParam)) { if (!session.isSpecificPermitted("cuba.gui.loginToClient")) { log.warn(String.format( "Attempt of login to %s for user '%s' without cuba.gui.loginToClient permission", clientTypeParam, login)); throw new LoginException(getInvalidCredentialsMessage(login, userLocale)); } } } }