/* * #%L * carewebframework * %% * Copyright (C) 2008 - 2016 Regenstrief Institute, Inc. * %% * 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. * * This Source Code Form is also subject to the terms of the Health-Related * Additional Disclaimer of Warranty and Limitation of Liability available at * * http://www.carewebframework.org/licensing/disclaimer. * * #L% */ package org.carewebframework.security.spring.controller; import java.util.HashMap; import java.util.Map; import org.carewebframework.api.domain.IUser; import org.carewebframework.api.security.SecurityUtil; import org.carewebframework.common.StrUtil; import org.carewebframework.security.spring.Constants; import org.carewebframework.ui.zk.ZKUtil; import org.springframework.security.authentication.CredentialsExpiredException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.WebAttributes; import org.springframework.security.web.savedrequest.SavedRequest; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zk.ui.util.GenericForwardComposer; import org.zkoss.zul.Button; import org.zkoss.zul.Timer; import org.zkoss.zul.impl.InputElement; import org.zkoss.zul.impl.MeshElement; /** * Controller for the login component. */ public class LoginWindowController extends GenericForwardComposer<Component> { private static final long serialVersionUID = 1L; private Component loginForm; private Timer timer; private SavedRequest savedRequest; private final String loginPaneUrl; private final String passwordPaneUrl; private final EventListener<Event> changeListener = new EventListener<Event>() { @Override public void onEvent(Event event) throws Exception { resetTimer(); } }; /** * If this authentication exception (or its cause) is of the expected type, return it. * Otherwise, return null. * * @param exc The authentication exception. * @param clazz The desired type. * @return The original exception or its cause if one of them is of the expected type. */ @SuppressWarnings("unchecked") protected static <T extends AuthenticationException> T getException(AuthenticationException exc, Class<T> clazz) { if (exc != null) { if (clazz.isInstance(exc)) { return (T) exc; } else if (clazz.isInstance(exc.getCause())) { return (T) exc.getCause(); } } return null; } public LoginWindowController(String loginPaneUrl, String passwordPaneUrl) { super(); this.loginPaneUrl = loginPaneUrl; this.passwordPaneUrl = passwordPaneUrl; } /** * Initialize the login form. * * @param comp The top level component. */ @Override public void doAfterCompose(Component comp) throws Exception { super.doAfterCompose(comp); timer.setDelay(execution.getSession().getMaxInactiveInterval() * 500); savedRequest = (SavedRequest) session.removeAttribute(org.carewebframework.security.spring.Constants.SAVED_REQUEST); AuthenticationException authError = (AuthenticationException) session .removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); IUser user = (IUser) session.removeAttribute(org.carewebframework.security.spring.Constants.SAVED_USER); Map<Object, Object> args = new HashMap<>(); args.put("savedRequest", savedRequest); args.put("authError", authError); String form; String title; if (user != null && authError instanceof CredentialsExpiredException && SecurityUtil.getSecurityService().canChangePassword()) { args.put("user", user); form = passwordPaneUrl; title = Constants.LBL_PASSWORD_CHANGE_PAGE_TITLE; } else { form = loginPaneUrl; title = Constants.LBL_LOGIN_PAGE_TITLE; } wireListener(ZKUtil.loadZulPage(form, loginForm, args)); getPage().setTitle(StrUtil.getLabel(title)); resetTimer(); } /** * Wire change listener to all input elements of child form. * * @param root Root element. */ private void wireListener(Component root) { for (Component child : root.getChildren()) { if (child instanceof MeshElement) { child.addEventListener(Events.ON_SELECT, changeListener); } else if (child instanceof InputElement) { child.addEventListener(Events.ON_CHANGING, changeListener); } else if (child instanceof Button) { child.addEventListener(Events.ON_CLICK, changeListener); } else { wireListener(child); } } } /** * Callback to start the timer. This must be done in a separate execution from the call to * timer.stop. Otherwise, the timer will not be reset. */ public void onResetTimer$timer() { if (timer != null) { timer.start(); } } /** * Invoked when inactivity timeout has occurred. */ public void onTimer$timer() { close(StrUtil.getLabel(Constants.LBL_LOGIN_FORM_TIMEOUT_MESSAGE)); } /** * Process a form submission request from another controller. */ public void onSubmit() { timer.stop(); timer = null; Clients.submitForm(loginForm); } /** * Process a close request from another controller. * * @param event Close event. Data field contains message to display. */ public void onClose(Event event) { close((String) event.getData()); } /** * Close the dialog and display the specified message. * * @param message The message text. */ private void close(String message) { SecurityUtil.getSecurityService().logout(true, savedRequest == null ? null : savedRequest.getRedirectUrl(), message); } /** * Restarts the timer. */ private void resetTimer() { if (timer != null) { timer.stop(); Events.echoEvent("onResetTimer", timer, null); } } }