Clover coverage report - Acegi Security System for Spring - 1.0.0-RC1
Coverage timestamp: Mon Dec 5 2005 09:05:15 EST
file stats: LOC: 177   Methods: 9
NCLOC: 99   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ConcurrentSessionControllerImpl.java 87.5% 94.4% 88.9% 91.8%
coverage coverage
 1    /* Copyright 2004, 2005 Acegi Technology Pty Limited
 2    *
 3    * Licensed under the Apache License, Version 2.0 (the "License");
 4    * you may not use this file except in compliance with the License.
 5    * You may obtain a copy of the License at
 6    *
 7    * http://www.apache.org/licenses/LICENSE-2.0
 8    *
 9    * Unless required by applicable law or agreed to in writing, software
 10    * distributed under the License is distributed on an "AS IS" BASIS,
 11    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    * See the License for the specific language governing permissions and
 13    * limitations under the License.
 14    */
 15   
 16    package org.acegisecurity.concurrent;
 17   
 18    import org.acegisecurity.AcegiMessageSource;
 19    import org.acegisecurity.Authentication;
 20    import org.acegisecurity.AuthenticationException;
 21    import org.springframework.beans.factory.InitializingBean;
 22    import org.springframework.context.MessageSource;
 23    import org.springframework.context.MessageSourceAware;
 24    import org.springframework.context.support.MessageSourceAccessor;
 25    import org.springframework.util.Assert;
 26   
 27   
 28    /**
 29    * Base implementation of {@link ConcurrentSessionControllerImpl} which
 30    * prohibits simultaneous logins.
 31    *
 32    * <p>
 33    * By default uses {@link org.acegisecurity.concurrent.SessionRegistryImpl},
 34    * although any <code>SessionRegistry</code> may be used.
 35    * </p>
 36    */
 37    public class ConcurrentSessionControllerImpl
 38    implements ConcurrentSessionController, InitializingBean,
 39    MessageSourceAware {
 40    //~ Instance fields ========================================================
 41   
 42    protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
 43    private SessionRegistry sessionRegistry = new SessionRegistryImpl();
 44    private boolean exceptionIfMaximumExceeded = false;
 45    private int maximumSessions = 1;
 46   
 47    //~ Methods ================================================================
 48   
 49  2 public void afterPropertiesSet() throws Exception {
 50  2 Assert.notNull(sessionRegistry, "SessionRegistry required");
 51  1 Assert.isTrue(maximumSessions != 0,
 52    "MaximumLogins must be either -1 to allow unlimited logins, or a positive integer to specify a maximum");
 53  0 Assert.notNull(this.messages, "A message source must be set");
 54    }
 55   
 56    /**
 57    * Allows subclasses to customise behaviour when too many sessions are
 58    * detected.
 59    *
 60    * @param sessionId the session ID of the present request
 61    * @param sessions either <code>null</code> or all unexpired sessions
 62    * associated with the principal
 63    * @param allowableSessions DOCUMENT ME!
 64    * @param registry an instance of the <code>SessionRegistry</code> for
 65    * subclass use
 66    *
 67    * @throws ConcurrentLoginException DOCUMENT ME!
 68    */
 69  2 protected void allowableSessionsExceeded(String sessionId,
 70    SessionInformation[] sessions, int allowableSessions,
 71    SessionRegistry registry) {
 72  2 if (exceptionIfMaximumExceeded || (sessions == null)) {
 73  1 throw new ConcurrentLoginException(messages.getMessage(
 74    "ConcurrentSessionControllerImpl.exceededAllowed",
 75    new Object[] {new Integer(allowableSessions)},
 76    "Maximum sessions of {0} for this principal exceeded"));
 77    }
 78   
 79    // Determine least recently used session, and mark it for invalidation
 80  1 SessionInformation leastRecentlyUsed = null;
 81   
 82  1 for (int i = 0; i < sessions.length; i++) {
 83  1 if ((leastRecentlyUsed == null)
 84    || sessions[i].getLastRequest()
 85    .before(leastRecentlyUsed.getLastRequest())) {
 86  1 leastRecentlyUsed = sessions[i];
 87    }
 88    }
 89   
 90  1 leastRecentlyUsed.expireNow();
 91    }
 92   
 93  4 public void checkAuthenticationAllowed(Authentication request)
 94    throws AuthenticationException {
 95  4 Assert.notNull(request,
 96    "Authentication request cannot be null (violation of interface contract)");
 97   
 98  4 Object principal = SessionRegistryUtils
 99    .obtainPrincipalFromAuthentication(request);
 100  4 String sessionId = SessionRegistryUtils
 101    .obtainSessionIdFromAuthentication(request);
 102   
 103  4 SessionInformation[] sessions = sessionRegistry.getAllSessions(principal);
 104   
 105  4 int sessionCount = 0;
 106   
 107  4 if (sessions != null) {
 108  3 sessionCount = sessions.length;
 109    }
 110   
 111  4 int allowableSessions = getMaximumSessionsForThisUser(request);
 112  4 Assert.isTrue(allowableSessions != 0,
 113    "getMaximumSessionsForThisUser() must return either -1 to allow unlimited logins, or a positive integer to specify a maximum");
 114   
 115  4 if (sessionCount < allowableSessions) {
 116  1 return;
 117  3 } else if (sessionCount == allowableSessions) {
 118    // Only permit it though if this request is associated with one of the sessions
 119  3 for (int i = 0; i < sessionCount; i++) {
 120  3 if (sessions[i].getSessionId().equals(sessionId)) {
 121  1 return;
 122    }
 123    }
 124    }
 125   
 126  2 allowableSessionsExceeded(sessionId, sessions,
 127    allowableSessions, sessionRegistry);
 128    }
 129   
 130    /**
 131    * Method intended for use by subclasses to override the maximum
 132    * number of sessions that are permitted for a particular
 133    * authentication. The default implementation simply returns the
 134    * <code>maximumSessions</code> value for the bean.
 135    *
 136    * @param authentication to determine the maximum sessions for
 137    *
 138    * @return either -1 meaning unlimited, or a positive integer to
 139    * limit (never zero)
 140    */
 141  4 protected int getMaximumSessionsForThisUser(
 142    Authentication authentication) {
 143  4 return maximumSessions;
 144    }
 145   
 146  3 public void registerSuccessfulAuthentication(
 147    Authentication authentication) {
 148  3 Assert.notNull(authentication,
 149    "Authentication cannot be null (violation of interface contract)");
 150   
 151  3 Object principal = SessionRegistryUtils
 152    .obtainPrincipalFromAuthentication(authentication);
 153  3 String sessionId = SessionRegistryUtils
 154    .obtainSessionIdFromAuthentication(authentication);
 155   
 156  3 sessionRegistry.removeSessionInformation(sessionId);
 157  3 sessionRegistry.registerNewSession(sessionId, principal);
 158    }
 159   
 160  2 public void setExceptionIfMaximumExceeded(
 161    boolean exceptionIfMaximumExceeded) {
 162  2 this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded;
 163    }
 164   
 165  1 public void setMaximumSessions(int maximumSessions) {
 166  1 this.maximumSessions = maximumSessions;
 167    }
 168   
 169  0 public void setMessageSource(MessageSource messageSource) {
 170  0 this.messages = new MessageSourceAccessor(messageSource);
 171    }
 172   
 173  2 public void setSessionRegistry(
 174    SessionRegistry sessionRegistry) {
 175  2 this.sessionRegistry = sessionRegistry;
 176    }
 177    }