/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.isis.viewer.wicket.viewer.integration.wicket; import java.util.Arrays; import java.util.List; import org.apache.wicket.Session; import org.apache.wicket.authroles.authentication.AuthenticatedWebSession; import org.apache.wicket.authroles.authorization.strategies.role.Roles; import org.apache.wicket.request.Request; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.isis.applib.clock.Clock; import org.apache.isis.applib.services.session.SessionLoggingService; import org.apache.isis.core.commons.authentication.AuthenticationSession; import org.apache.isis.core.runtime.authentication.AuthenticationManager; import org.apache.isis.core.runtime.authentication.AuthenticationRequest; import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword; import org.apache.isis.core.runtime.system.context.IsisContext; import org.apache.isis.core.runtime.system.session.IsisSessionFactory; import org.apache.isis.viewer.wicket.model.models.BookmarkedPagesModel; import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbModel; import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbModelProvider; import org.apache.isis.viewer.wicket.ui.pages.BookmarkedPagesModelProvider; /** * Viewer-specific implementation of {@link AuthenticatedWebSession}, which * delegates to the Isis' configured {@link AuthenticationManager}, and which * also tracks thread usage (so that multiple concurrent requests are all * associated with the same session). */ public class AuthenticatedWebSessionForIsis extends AuthenticatedWebSession implements BreadcrumbModelProvider, BookmarkedPagesModelProvider { private static final long serialVersionUID = 1L; public static final String USER_ROLE = "org.apache.isis.viewer.wicket.roles.USER"; public static AuthenticatedWebSessionForIsis get() { return (AuthenticatedWebSessionForIsis) Session.get(); } private final BookmarkedPagesModel bookmarkedPagesModel = new BookmarkedPagesModel(); private final BreadcrumbModel breadcrumbModel = new BreadcrumbModel(); private AuthenticationSession authenticationSession; public AuthenticatedWebSessionForIsis(final Request request) { super(request); } @Override public synchronized boolean authenticate(final String username, final String password) { AuthenticationRequest authenticationRequest = new AuthenticationRequestPassword(username, password); authenticationRequest.setRoles(Arrays.asList(USER_ROLE)); authenticationSession = getAuthenticationManager().authenticate(authenticationRequest); if (authenticationSession != null) { log(SessionLoggingService.Type.LOGIN, username, null); return true; } else { return false; } } @Override public synchronized void invalidateNow() { // similar code in Restful Objects viewer (UserResourceServerside#logout) // this needs to be done here because Wicket will expire the HTTP session // while the Shiro authenticator uses the session to obtain the details of the principals for it to logout // // org.apache.catalina.session.StandardSession.getAttribute(StandardSession.java:1195) // org.apache.catalina.session.StandardSessionFacade.getAttribute(StandardSessionFacade.java:108) // org.apache.shiro.web.session.HttpServletSession.getAttribute(HttpServletSession.java:146) // org.apache.shiro.session.ProxiedSession.getAttribute(ProxiedSession.java:121) // org.apache.shiro.subject.support.DelegatingSubject.getRunAsPrincipalsStack(DelegatingSubject.java:469) // org.apache.shiro.subject.support.DelegatingSubject.getPrincipals(DelegatingSubject.java:153) // org.apache.shiro.mgt.DefaultSecurityManager.logout(DefaultSecurityManager.java:547) // org.apache.shiro.subject.support.DelegatingSubject.logout(DelegatingSubject.java:363) // org.apache.isis.security.shiro.ShiroAuthenticatorOrAuthorizor.logout(ShiroAuthenticatorOrAuthorizor.java:179) // org.apache.isis.core.runtime.authentication.standard.AuthenticationManagerStandard.closeSession(AuthenticationManagerStandard.java:141) getAuthenticationManager().closeSession(authenticationSession); getIsisSessionFactory().closeSession(); super.invalidateNow(); } @Override public synchronized void onInvalidate() { super.onInvalidate(); SessionLoggingService.CausedBy causedBy = RequestCycle.get() != null ? SessionLoggingService.CausedBy.USER : SessionLoggingService.CausedBy.SESSION_EXPIRATION; String userName = null; if (authenticationSession != null) { userName = authenticationSession.getUserName(); } log(SessionLoggingService.Type.LOGOUT, userName, causedBy); } public synchronized AuthenticationSession getAuthenticationSession() { return authenticationSession; } @Override public synchronized Roles getRoles() { if (!isSignedIn()) { return null; } final List<String> roles = authenticationSession.getRoles(); return new Roles(roles.toArray(new String[roles.size()])); } @Override public synchronized void detach() { breadcrumbModel.detach(); super.detach(); } // ///////////////////////////////////////////////// // Breadcrumbs and Bookmarks support // ///////////////////////////////////////////////// @Override public BreadcrumbModel getBreadcrumbModel() { return breadcrumbModel; } @Override public BookmarkedPagesModel getBookmarkedPagesModel() { return bookmarkedPagesModel; } // ///////////////////////////////////////////////// // Dependencies // ///////////////////////////////////////////////// protected AuthenticationManager getAuthenticationManager() { return getIsisSessionFactory().getAuthenticationManager(); } // ///////////////////////////////////////////////// // *Provider impl. // ///////////////////////////////////////////////// private void log( final SessionLoggingService.Type type, final String username, final SessionLoggingService.CausedBy causedBy) { final SessionLoggingService sessionLoggingService = getSessionLoggingService(); if (sessionLoggingService != null) { getIsisSessionFactory().doInSession(new Runnable() { @Override public void run() { // use hashcode as session identifier, to avoid re-binding http sessions if using Session#getId() int sessionHashCode = System.identityHashCode(AuthenticatedWebSessionForIsis.this); sessionLoggingService.log(type, username, Clock.getTimeAsDateTime().toDate(), causedBy, Integer.toString(sessionHashCode)); } }); } } protected SessionLoggingService getSessionLoggingService() { return getIsisSessionFactory().getServicesInjector().lookupService(SessionLoggingService.class); } @Override public synchronized void replaceSession() { // do nothing here because this will lead to problems with Shiro // see https://issues.apache.org/jira/browse/ISIS-1018 } IsisSessionFactory getIsisSessionFactory() { return IsisContext.getSessionFactory(); } }