Java tutorial
package de.metas.ui.web.login; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.adempiere.ad.api.ILanguageBL; import org.adempiere.exceptions.AdempiereException; import org.adempiere.util.Check; import org.adempiere.util.Services; import org.compiere.model.MSession; import org.compiere.util.Env; import org.compiere.util.KeyNamePair; import org.compiere.util.Login; import org.compiere.util.LoginContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.session.events.SessionDestroyedEvent; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.google.common.base.Joiner; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; import de.metas.ui.web.base.session.UserPreference; import de.metas.ui.web.config.WebConfig; import de.metas.ui.web.login.exceptions.NotAuthenticatedException; import de.metas.ui.web.login.json.JSONLoginAuthRequest; import de.metas.ui.web.login.json.JSONLoginAuthResponse; import de.metas.ui.web.login.json.JSONLoginRole; import de.metas.ui.web.notification.UserNotificationsService; import de.metas.ui.web.session.UserSession; import de.metas.ui.web.window.datatypes.json.JSONLookupValue; import de.metas.ui.web.window.datatypes.json.JSONLookupValuesList; /* * #%L * metasfresh-webui-api * %% * Copyright (C) 2016 metas GmbH * %% * This program 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. * * This program 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 this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ @RestController @RequestMapping(value = LoginRestController.ENDPOINT) public class LoginRestController { public static final String ENDPOINT = WebConfig.ENDPOINT_ROOT + "/login"; @Autowired private UserSession userSession; @Autowired private UserNotificationsService userNotificationsService; private Login getLoginService() { return new Login(userSession.getCtx()); } private void assertAuthenticated() { getLoginService().getCtx().getAD_User_ID_IfExists().orElseThrow(() -> new NotAuthenticatedException()); } @PostMapping("/authenticate") public JSONLoginAuthResponse authenticate(@RequestBody final JSONLoginAuthRequest request) { userSession.assertNotLoggedIn(); final Login loginService = getLoginService(); final MSession session = createMSession(loginService); try { final Set<KeyNamePair> availableRoles = loginService.authenticate(request.getUsername(), request.getPassword()); // // Create JSON roles final Set<JSONLoginRole> jsonRoles = createJSONLoginRoles(loginService, availableRoles); if (jsonRoles.size() == 1) { final JSONLoginRole loginRole = jsonRoles.iterator().next(); loginComplete(loginRole); return JSONLoginAuthResponse.loginComplete(loginRole); } return JSONLoginAuthResponse.of(jsonRoles); } catch (final Exception ex) { userSession.setLoggedIn(false); destroySession(loginService, session); throw Throwables.propagate(ex); } } private Set<JSONLoginRole> createJSONLoginRoles(final Login loginService, final Set<KeyNamePair> availableRoles) { if (availableRoles.isEmpty()) { return ImmutableSet.of(); } final LoginContext ctx = loginService.getCtx(); final ImmutableSet.Builder<JSONLoginRole> jsonRoles = ImmutableSet.builder(); for (final KeyNamePair role : availableRoles) { final int AD_Role_ID = role.getKey(); final int AD_User_ID = ctx.getAD_User_ID(); for (final KeyNamePair tenant : loginService.getAvailableClients(AD_Role_ID, AD_User_ID)) { final int AD_Client_ID = tenant.getKey(); final Set<KeyNamePair> availableOrgs = loginService.getAvailableOrgs(AD_Role_ID, AD_User_ID, AD_Client_ID); for (final KeyNamePair org : availableOrgs) { // If there is more than one available Org, then skip the "*" org if (availableOrgs.size() > 1 && org.getKey() == Env.CTXVALUE_AD_Org_ID_Any) { continue; } final String caption = Joiner.on(", ").join(role.getName(), tenant.getName(), org.getName()); final JSONLoginRole jsonRole = JSONLoginRole.of(caption, AD_Role_ID, AD_Client_ID, org.getKey()); jsonRoles.add(jsonRole); } } } return jsonRoles.build(); } private static MSession createMSession(final Login loginService) { final HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder .currentRequestAttributes()).getRequest(); final HttpSession httpSess = httpRequest.getSession(); final String webSessionId = httpSess.getId(); // // final WebBrowser webBrowser = Page.getCurrent().getWebBrowser(); String remoteAddr = httpRequest.getRemoteAddr(); String remoteHost = httpRequest.getRemoteHost(); // // Check if we are behind proxy and if yes, get the actual client IP address // NOTE: when configuring apache, don't forget to activate reverse-proxy mode // see http://www.xinotes.org/notes/note/770/ final String forwardedFor = httpRequest.getHeader("X-Forwarded-For"); if (!Check.isEmpty(forwardedFor)) { remoteAddr = forwardedFor; remoteHost = forwardedFor; } final LoginContext ctx = loginService.getCtx(); final MSession sessionPO = MSession.get(ctx.getSessionContext(), remoteAddr, remoteHost, webSessionId); // Set HostKey // FIXME: commented out because this one is not working when running over websockets (i.e. HttpServletResponse does not exists) // see https://dev.vaadin.com/ticket/11808 // @formatter:off // final I_AD_Session session = InterfaceWrapperHelper.create(sessionPO, I_AD_Session.class); // HttpCookieHostKeyStorage.createUpdateHostKey(); // final String hostKey = hostKeyBL.getHostKey(); // session.setHostKey(hostKey); // InterfaceWrapperHelper.save(session); // @formatter:on // Update Login helper loginService.setRemoteAddr(remoteAddr); loginService.setRemoteHost(remoteHost); loginService.setWebSession(webSessionId); return sessionPO; } private static void destroySession(final Login loginService, final MSession session) { if (session != null) { session.logout(); } if (loginService != null) { loginService.getCtx().resetAD_Session_ID(); } // // Destroy http session final ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder .currentRequestAttributes(); final HttpSession httpSession = servletRequestAttributes.getRequest().getSession(false); if (httpSession != null) { httpSession.invalidate(); } } @RequestMapping(value = "/loginComplete", method = RequestMethod.POST) public void loginComplete(@RequestBody final JSONLoginRole loginRole) { assertAuthenticated(); userSession.assertNotLoggedIn(); final KeyNamePair role = KeyNamePair.of(loginRole.getRoleId()); final KeyNamePair tenant = KeyNamePair.of(loginRole.getTenantId()); final KeyNamePair org = KeyNamePair.of(loginRole.getOrgId()); final KeyNamePair warehouse = null; // // Update context final Login loginService = getLoginService(); // TODO: optimize loginService.setRoleAndGetClients(role); loginService.setClientAndGetOrgs(tenant); // // Load preferences and export them to context final LoginContext ctx = loginService.getCtx(); final UserPreference userPreference = userSession.getUserPreference(); userPreference.loadPreference(ctx.getSessionContext()); userPreference.updateContext(ctx.getSessionContext()); // // Validate login: fires login complete model interceptors { final String msg = loginService.validateLogin(org); if (!Check.isEmpty(msg, true)) { throw new AdempiereException(msg); } } // // Load preferences { final java.sql.Timestamp date = null; final String msg = loginService.loadPreferences(org, warehouse, date); if (!Check.isEmpty(msg, true)) { throw new AdempiereException(msg); } } // // Save user preferences final LoginContext loginCtx = loginService.getCtx(); // userPreference.setProperty(UserPreference.P_LANGUAGE, Env.getContext(Env.getCtx(), UserPreference.LANGUAGE_NAME)); userPreference.setProperty(UserPreference.P_ROLE, loginCtx.getAD_Role_ID()); userPreference.setProperty(UserPreference.P_CLIENT, loginCtx.getAD_Client_ID()); userPreference.setProperty(UserPreference.P_ORG, loginCtx.getAD_Org_ID()); userPreference.setProperty(UserPreference.P_WAREHOUSE, loginCtx.getM_Warehouse_ID()); userPreference.savePreference(); // // Mark session as logged in userSession.setLoggedIn(true); // // Enable user notifications userNotificationsService.enableForSession(userSession.getSessionId(), userSession.getAD_User_ID(), userSession.getAD_Language()); } @RequestMapping(value = "/isLoggedIn", method = RequestMethod.GET) public boolean isLoggedIn() { return userSession.isLoggedIn(); } @RequestMapping(value = "/language", method = RequestMethod.PUT) public String setAD_Language(@RequestBody final String adLanguage) { userSession.setAD_Language(adLanguage); final String adLanguageNew = userSession.getAD_Language(); return adLanguageNew; } @RequestMapping(value = "/language", method = RequestMethod.GET) public String getAD_Language() { return userSession.getAD_Language(); } @RequestMapping(value = "/availableLanguages", method = RequestMethod.GET) public JSONLookupValuesList getAvailableLanguages() { return Services.get(ILanguageBL.class).getAvailableLanguages(userSession.getCtx()).stream() .map(adLanguageObj -> JSONLookupValue.of(adLanguageObj.getAD_Language(), adLanguageObj.getName())) .collect(JSONLookupValuesList.collect()).setDefaultValue(userSession.getAD_Language()); } @RequestMapping(value = "/logout", method = RequestMethod.GET) public void logout(final HttpServletRequest request) { userSession.assertLoggedIn(); final Login loginService = getLoginService(); final MSession session = MSession.get(userSession.getCtx(), false); destroySession(loginService, session); } @Component public static class SessionDestroyedListener implements ApplicationListener<SessionDestroyedEvent> { @Autowired private UserNotificationsService userNotificationsService; public SessionDestroyedListener() { super(); } @Override public void onApplicationEvent(final SessionDestroyedEvent event) { final String sessionId = event.getSessionId(); userNotificationsService.disableForSession(sessionId); } } }