cleanup, add checks to arguments and responses, add log statements
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / SessionManager.java
index 7036016..c8a2f90 100644 (file)
@@ -1,4 +1,20 @@
 /*
+ * Copyright [2005] [University Corporation for Advanced Internet Development, 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.
+ */
+
+/*
  * SessionManager creates, maintains, and caches Session objects.
  * 
  * The SessionManager is a singleton object.
@@ -9,15 +25,6 @@
  * of this class so that the in-memory collection and any disk Cache can
  * also be changed. Disk cache implementations are referenced through the
  * SessionCache interface. 
- * 
- * --------------------
- * Copyright 2002, 2004 
- * University Corporation for Advanced Internet Development, Inc. 
- * All rights reserved
- * [Thats all we have to say to protect ourselves]
- * Your permission to use this code is governed by "The Shibboleth License".
- * A copy may be found at http://shibboleth.internet2.edu/license.html
- * [Nothing in copyright law requires license text in every file.]
  */
 package edu.internet2.middleware.shibboleth.serviceprovider;
 
@@ -71,85 +78,131 @@ public class SessionManager {
        public String generateKey() {
            byte[] trash = new byte[16];
            char[] ctrash = new char[16];
+               String key;
            do {
                rand.nextBytes(trash);
                for (int i=0;i<16;i++) {
                    trash[i]&=0x3f;
                    ctrash[i]=(char)table.charAt(trash[i]);
                }
-           } while (null!=sessions.get(ctrash));
-           return new String(ctrash);
+                       key=new String(ctrash);
+           } while (null!=sessions.get(key));
+           return key;
        }
        
        
        
        public synchronized Session findSession(String sessionId, String applicationId ) {
+               if (sessionId==null || applicationId==null)
+                       throw new IllegalArgumentException();
                Session s = (Session) sessions.get(sessionId);
-               if (s==null)
+               if (s==null) {
+                       log.warn("Session not found with ID "+sessionId);
                        return null;
-               if (null==s.getAuthenticationAssertion())
+               }
+               if (null==s.getAuthenticationAssertion()) {
+                       log.warn("Uninitialized (reserved) Session has ID "+sessionId);
                    return null;
-               if (!applicationId.equals(s.getApplicationId()))
+               }
+               if (!applicationId.equals(s.getApplicationId())) {
+                       log.error("Session ID "+sessionId+" doesn't match application "+applicationId);
                        return null;
+               }
+               if (s.isExpired()) {
+                       log.error("Session ID "+sessionId+" has expired.");
+                       // return null;
+               }
+               s.renew();
                return s;
        }
 
        private synchronized Session findEmptySession(String sessionId) {
+               if (sessionId==null)
+                       throw new IllegalArgumentException();
                Session s = (Session) sessions.get(sessionId);
-               if (s==null)
+               if (s==null) {
+                       log.warn("Session not found with ID "+sessionId);
                        return null;
-               if (null!=s.getAuthenticationAssertion())
+               }
+               if (null!=s.getAuthenticationAssertion()){
+                       log.error("Active Session found when looking for reserved ID:"+sessionId);
                    return null;
+               }
+               s.renew();
                return s;
        }
        
        
        protected synchronized void add(Session s) {
+               if (s==null)
+                       throw new IllegalArgumentException();
+               log.debug("Session added: "+s.getKey());
                sessions.put(s.getKey(), s);
                if (cache!=null)
                        cache.add(s);
        }
        
        protected synchronized void update(Session s) {
+               if (s==null)
+                       throw new IllegalArgumentException();
+               s.renew();
+               log.debug("Session updated: "+s.getKey());
                sessions.put(s.getKey(), s);
                if (cache!=null)
                        cache.update(s);
        }
        
        protected synchronized void remove(Session s) {
+               if (s==null)
+                       throw new IllegalArgumentException();
+               log.debug("Session removed: "+s.getKey());
                sessions.remove(s.getKey());
                if (cache!=null)
                        cache.remove(s);
        }
        
-
-       /**
-        * Test for valid Session
-        * 
-        * @param sessionId      typically, the cookie value from client browser
-        * @param applicationId  id of target application asking about session
-        * @param ipaddr         null, or IP address of client
-        * @return
-        */
-       public 
-                       boolean 
-       isValid(
-                       String sessionId,   
-                       String applicationId, 
-                       String ipaddr         
-                       ){
-               Session session = findSession(sessionId,applicationId);
-               ServiceProviderConfig.ApplicationInfo application = context.getServiceProviderConfig().getApplication(applicationId);
-               if (session==null)
-                       return false; // Cookie value did not match cached session
-               if (application == null)
-                       return false; // ApplicationConfig ID invalid
-               if (ipaddr!=null && !ipaddr.equals(session.getIpaddr()))
-                       return false; // Client coming from a different machine
-               // check for timeout
-               // Note: RPC prefetches attributes here
-               return true;
+       protected synchronized void expireSessions() {
+               Iterator iterator = sessions.entrySet().iterator();
+               while (iterator.hasNext()) {
+                       Map.Entry entry = (Map.Entry) iterator.next();
+                       Session session = (Session) entry.getValue();
+                       if (session.isExpired()) {
+                               log.info("Session " + session.getKey() + " has expired.");
+                               iterator.remove();
+                       }
+               }
        }
+       
+//  This was generated from a C++ routine, but it doesn't seem to be needed
+//     /**
+//      * Test for valid Session
+//      * 
+//      * @param sessionId      typically, the cookie value from client browser
+//      * @param applicationId  id of target application asking about session
+//      * @param ipaddr         null, or IP address of client
+//      * @return
+//      */
+//     public 
+//                     boolean 
+//     isValid(
+//                     String sessionId,   
+//                     String applicationId, 
+//                     String ipaddr         
+//                     ){
+//             if (sessionId==null || applicationId==null)
+//                     throw new IllegalArgumentException();
+//             Session session = findSession(sessionId,applicationId);
+//             ServiceProviderConfig.ApplicationInfo application = context.getServiceProviderConfig().getApplication(applicationId);
+//             if (session==null)
+//                     return false; // Cookie value did not match cached session
+//             if (application == null)
+//                     return false; // ApplicationConfig ID invalid
+//             if (ipaddr!=null && !ipaddr.equals(session.getIpaddr()))
+//                     return false; // Client coming from a different machine
+//             // check for timeout
+//             // Note: RPC prefetches attributes here
+//             return true;
+//     }
 
        
        /**
@@ -179,6 +232,7 @@ public class SessionManager {
                Sessions appSessionValues = appinfo.getApplicationConfig().getSessions();
                
                String sessionId = null;
+               boolean isUpdate = false;
                
                Session session;
                if (emptySessionId==null) {
@@ -187,6 +241,8 @@ public class SessionManager {
                    session = findEmptySession(emptySessionId);
                    if (session==null) {
                            session = new Session(generateKey());
+                   } else {
+                       isUpdate=true;
                    }
                }
                session.setApplicationId(applicationId);
@@ -196,17 +252,45 @@ public class SessionManager {
                session.setAuthenticationAssertion(assertion);
                session.setAuthenticationStatement(authenticationStatement);
                
-               session.setLifetime(appSessionValues.getLifetime());
-               session.setTimeout(appSessionValues.getTimeout());
+               // Get lifetime and timeout from Applications/Sessions in config file 
+               session.setLifetime(appSessionValues.getLifetime()*1000);
+               session.setTimeout(appSessionValues.getTimeout()*1000);
                
                sessionId = session.getKey();
 
-               // This static method finds its unique instance variable
-               add(session);
+               if (isUpdate)
+                       update(session);
+               else
+                       add(session);
+               
            log.debug("New Session created "+sessionId);
 
                return sessionId;
        }
+       public 
+       String 
+reserveSession(
+       String applicationId 
+       ){
+
+ServiceProviderConfig config = context.getServiceProviderConfig();
+ApplicationInfo appinfo = config.getApplication(applicationId);
+Sessions appSessionValues = appinfo.getApplicationConfig().getSessions();
+
+String sessionId = null;
+boolean isUpdate = false;
+
+Session session= new Session(generateKey());
+session.setApplicationId(applicationId);
+
+sessionId = session.getKey();
+
+add(session);
+
+log.debug("SessionId reserved "+sessionId);
+
+return sessionId;
+}
        /**
         * <p>IOC wiring point to plug in an external SessionCache implementation.
         * </p>
@@ -217,6 +301,8 @@ public class SessionManager {
        setCache(
                        SessionCache cache) {
                
+               if (cache==null)
+                       throw new IllegalArgumentException();
            log.info("Enabling Session Cache");
                /*
                 * The following code supports dynamic switching from
@@ -330,5 +416,4 @@ public class SessionManager {
            return attributeMap;
        }
        
-       
 }