JSEC-37 - architectural preparation to enable easy assumed identity support.  Need to vet modifications before they can be verified as the final solution.

git-svn-id: https://svn.apache.org/repos/asf/incubator/jsecurity/trunk@734355 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/org/jsecurity/mgt/DefaultSecurityManager.java b/core/src/org/jsecurity/mgt/DefaultSecurityManager.java
index c9adf89..5487675 100644
--- a/core/src/org/jsecurity/mgt/DefaultSecurityManager.java
+++ b/core/src/org/jsecurity/mgt/DefaultSecurityManager.java
@@ -26,10 +26,12 @@
 import org.jsecurity.realm.Realm;

 import org.jsecurity.session.InvalidSessionException;

 import org.jsecurity.session.Session;

-import org.jsecurity.subject.*;

+import org.jsecurity.subject.AbstractRememberMeManager;

+import org.jsecurity.subject.PrincipalCollection;

+import org.jsecurity.subject.RememberMeManager;

+import org.jsecurity.subject.Subject;

 import org.jsecurity.util.ThreadContext;

 

-import java.net.InetAddress;

 import java.util.Collection;

 

 /**

@@ -75,10 +77,16 @@
 

     protected RememberMeManager rememberMeManager;

 

+    protected SubjectFactory subjectFactory;

+

+    protected SubjectBinder subjectBinder;

+

     /**

      * Default no-arg constructor.

      */

     public DefaultSecurityManager() {

+        setSubjectBinder(new SessionSubjectBinder());

+        setSubjectFactory(new DefaultSubjectFactory(this));

     }

 

     /**

@@ -87,6 +95,7 @@
      * @param singleRealm the single realm used by this SecurityManager.

      */

     public DefaultSecurityManager(Realm singleRealm) {

+        this();

         setRealm(singleRealm);

     }

 

@@ -96,9 +105,26 @@
      * @param realms the realm instances backing this SecurityManager.

      */

     public DefaultSecurityManager(Collection<Realm> realms) {

+        this();

         setRealms(realms);

     }

 

+    public SubjectFactory getSubjectFactory() {

+        return subjectFactory;

+    }

+

+    public void setSubjectFactory(SubjectFactory subjectFactory) {

+        this.subjectFactory = subjectFactory;

+    }

+

+    public SubjectBinder getSubjectBinder() {

+        return subjectBinder;

+    }

+

+    public void setSubjectBinder(SubjectBinder subjectBinder) {

+        this.subjectBinder = subjectBinder;

+    }

+

     public RememberMeManager getRememberMeManager() {

         return rememberMeManager;

     }

@@ -158,34 +184,9 @@
         getRememberMeManagerForCipherAttributes().setDecryptionCipherKeyBase64(base64);

     }

 

-    private void assertPrincipals(AuthenticationInfo info) {

-        PrincipalCollection principals = info.getPrincipals();

-        if (principals == null || principals.isEmpty()) {

-            String msg = "Authentication info returned from Authenticator must have non null and non empty principals.";

-            throw new IllegalArgumentException(msg);

-        }

-    }

-

     protected Subject createSubject() {

         PrincipalCollection principals = getRememberedIdentity();

-        return createSubject(principals);

-    }

-

-    protected Subject createSubject(PrincipalCollection subjectPrincipals) {

-        return createSubject(subjectPrincipals, null);

-    }

-

-    protected Subject createSubject(PrincipalCollection principals, Session existing) {

-        return createSubject(principals, existing, false);

-    }

-

-    protected Subject createSubject(PrincipalCollection principals, Session existing, boolean authenticated) {

-        return createSubject(principals, existing, authenticated, null);

-    }

-

-    protected Subject createSubject(PrincipalCollection principals, Session existing,

-                                    boolean authenticated, InetAddress inetAddress) {

-        return new DelegatingSubject(principals, authenticated, inetAddress, existing, this);

+        return getSubjectFactory().createSubject(principals, null, false, null);

     }

 

     /**

@@ -197,25 +198,7 @@
      *         authenticated user.

      */

     protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info) {

-        assertPrincipals(info);

-

-        //get any existing session that may exist - we don't want to lose it:

-        Subject subject = getSubject(false);

-        Session session = null;

-        if (subject != null) {

-            session = subject.getSession(false);

-        }

-

-        InetAddress authcSourceIP = null;

-        if (token instanceof InetAuthenticationToken) {

-            authcSourceIP = ((InetAuthenticationToken) token).getInetAddress();

-        }

-        if (authcSourceIP == null) {

-            //try the thread local:

-            authcSourceIP = ThreadContext.getInetAddress();

-        }

-

-        return createSubject(info.getPrincipals(), session, true, authcSourceIP);

+        return getSubjectFactory().createSubject(token, info, getSubject(false));

     }

 

     /**

@@ -228,10 +211,7 @@
      *                for later use.

      */

     protected void bind(Subject subject) {

-        if (log.isTraceEnabled()) {

-            log.trace("Binding Subject [" + subject + "] to a thread local...");

-        }

-        ThreadContext.bind(subject);

+        getSubjectBinder().bind(subject);

     }

 

     private void assertCreation(Subject subject) throws IllegalStateException {

@@ -358,16 +338,16 @@
         Subject subject = getSubject(false);

         if (subject != null) {

             try {

-                stopSession(subject);

-            } catch (Exception e) {

-                if (log.isDebugEnabled()) {

-                    String msg = "Unable to cleanly stop Session for Subject [" + subject.getPrincipal() + "] " +

-                            "Ignoring (logging out).";

-                    log.debug(msg, e);

-                }

-            }

-            try {

                 unbind(subject);

+                try {

+                    stopSession(subject);

+                } catch (Exception e) {

+                    if (log.isDebugEnabled()) {

+                        String msg = "Unable to cleanly stop Session for Subject [" + subject.getPrincipal() + "] " +

+                                "Ignoring (logging out).";

+                        log.debug(msg, e);

+                    }

+                }

             } catch (Exception e) {

                 if (log.isDebugEnabled()) {

                     String msg = "Unable to cleanly unbind Subject.  Ignoring (logging out).";

@@ -394,7 +374,7 @@
     }

 

     protected void unbind(Subject subject) {

-        ThreadContext.unbindSubject();

+        getSubjectBinder().unbind(subject);

     }

 

     protected PrincipalCollection getRememberedIdentity() {

@@ -414,7 +394,7 @@
     }

 

     protected Subject getSubject(boolean create) {

-        Subject subject = ThreadContext.getSubject();

+        Subject subject = getSubjectBinder().getSubject();

         if (subject == null && create) {

             subject = createSubject();

             bind(subject);

diff --git a/core/src/org/jsecurity/mgt/DefaultSubjectFactory.java b/core/src/org/jsecurity/mgt/DefaultSubjectFactory.java
new file mode 100644
index 0000000..a7f612c
--- /dev/null
+++ b/core/src/org/jsecurity/mgt/DefaultSubjectFactory.java
@@ -0,0 +1,98 @@
+/*
+ * 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.jsecurity.mgt;
+
+import org.jsecurity.authc.AuthenticationInfo;
+import org.jsecurity.authc.AuthenticationToken;
+import org.jsecurity.authc.InetAuthenticationToken;
+import org.jsecurity.session.Session;
+import org.jsecurity.subject.DelegatingSubject;
+import org.jsecurity.subject.PrincipalCollection;
+import org.jsecurity.subject.Subject;
+import org.jsecurity.util.ThreadContext;
+
+import java.net.InetAddress;
+
+/**
+ * TODO - Class JavaDoc
+ *
+ * @author Les Hazlewood
+ * @since 1.0
+ */
+public class DefaultSubjectFactory implements SubjectFactory {
+
+    private SecurityManager securityManager;
+
+    public DefaultSubjectFactory() {
+    }
+
+    public DefaultSubjectFactory(SecurityManager securityManager) {
+        setSecurityManager(securityManager);
+    }
+
+    public SecurityManager getSecurityManager() {
+        return securityManager;
+    }
+
+    public void setSecurityManager(SecurityManager securityManager) {
+        this.securityManager = securityManager;
+    }
+
+    public Subject createSubject(PrincipalCollection principals, Session existing,
+                                 boolean authenticated, InetAddress inetAddress) {
+        return new DelegatingSubject(principals, authenticated, inetAddress, existing, getSecurityManager());
+    }
+
+    private void assertPrincipals(AuthenticationInfo info) {
+        PrincipalCollection principals = info.getPrincipals();
+        if (principals == null || principals.isEmpty()) {
+            String msg = "AuthenticationInfo must have non null and non empty principals.";
+            throw new IllegalArgumentException(msg);
+        }
+    }
+
+    /**
+     * Creates a <tt>Subject</tt> instance for the user represented by the given method arguments.
+     *
+     * @param token the <tt>AuthenticationToken</tt> submitted for the successful authentication.
+     * @param info  the <tt>AuthenticationInfo</tt> of a newly authenticated user.
+     * @return the <tt>Subject</tt> instance that represents the user and session data for the newly
+     *         authenticated user.
+     */
+    public Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {
+        assertPrincipals(info);
+
+        //get any existing session that may exist - we don't want to lose it:
+        Session session = null;
+        if (existing != null) {
+            session = existing.getSession(false);
+        }
+
+        InetAddress authcSourceIP = null;
+        if (token instanceof InetAuthenticationToken) {
+            authcSourceIP = ((InetAuthenticationToken) token).getInetAddress();
+        }
+        if (authcSourceIP == null) {
+            //try the thread local:
+            authcSourceIP = ThreadContext.getInetAddress();
+        }
+
+        return createSubject(info.getPrincipals(), session, true, authcSourceIP);
+    }
+}
diff --git a/core/src/org/jsecurity/mgt/SessionSubjectBinder.java b/core/src/org/jsecurity/mgt/SessionSubjectBinder.java
new file mode 100644
index 0000000..0597541
--- /dev/null
+++ b/core/src/org/jsecurity/mgt/SessionSubjectBinder.java
@@ -0,0 +1,81 @@
+/*
+ * 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.jsecurity.mgt;
+
+import org.jsecurity.session.Session;
+import org.jsecurity.subject.PrincipalCollection;
+import org.jsecurity.subject.Subject;
+
+/**
+ * Binds the Subject to the accessible Session in addition to the ThreadContext.
+ *
+ * @author Les Hazlewood
+ * @since 1.0
+ */
+public class SessionSubjectBinder extends ThreadContextSubjectBinder {
+
+    /**
+     * The key that is used to store subject principals in the session.
+     */
+    public static final String PRINCIPALS_SESSION_KEY = SessionSubjectBinder.class.getName() + "_PRINCIPALS_SESSION_KEY";
+
+    /**
+     * The key that is used to store whether or not the user is authenticated in the session.
+     */
+    public static final String AUTHENTICATED_SESSION_KEY = SessionSubjectBinder.class.getName() + "_AUTHENTICATED_SESSION_KEY";
+
+    @Override
+    public void bind(Subject subject) {
+        bindToSession(subject);
+        super.bind(subject);
+    }
+
+    protected void bindToSession(Subject subject) {
+        PrincipalCollection principals = subject.getPrincipals();
+        if (principals != null && !principals.isEmpty()) {
+            Session session = subject.getSession();
+            session.setAttribute(PRINCIPALS_SESSION_KEY, principals);
+        } else {
+            Session session = subject.getSession(false);
+            if (session != null) {
+                session.removeAttribute(PRINCIPALS_SESSION_KEY);
+            }
+        }
+
+        if (subject.isAuthenticated()) {
+            Session session = subject.getSession();
+            session.setAttribute(AUTHENTICATED_SESSION_KEY, subject.isAuthenticated());
+        } else {
+            Session session = subject.getSession(false);
+            if (session != null) {
+                session.removeAttribute(AUTHENTICATED_SESSION_KEY);
+            }
+        }
+    }
+
+    @Override
+    public void unbind(Subject subject) {
+        Session session = subject.getSession(false);
+        if (session != null) {
+            session.removeAttribute(PRINCIPALS_SESSION_KEY);
+            session.removeAttribute(AUTHENTICATED_SESSION_KEY);
+        }
+        super.unbind(subject);
+    }
+}
diff --git a/core/src/org/jsecurity/mgt/SubjectBinder.java b/core/src/org/jsecurity/mgt/SubjectBinder.java
new file mode 100644
index 0000000..d06b021
--- /dev/null
+++ b/core/src/org/jsecurity/mgt/SubjectBinder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.jsecurity.mgt;
+
+import org.jsecurity.subject.Subject;
+
+/**
+ * TODO - Class JavaDoc
+ *
+ * @author Les Hazlewood
+ * @since 1.0
+ */
+public interface SubjectBinder {
+
+    Subject getSubject();
+
+    void bind(Subject subject);
+
+    void unbind(Subject subject);
+}
diff --git a/core/src/org/jsecurity/mgt/SubjectFactory.java b/core/src/org/jsecurity/mgt/SubjectFactory.java
new file mode 100644
index 0000000..51c8712
--- /dev/null
+++ b/core/src/org/jsecurity/mgt/SubjectFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.jsecurity.mgt;
+
+import org.jsecurity.authc.AuthenticationInfo;
+import org.jsecurity.authc.AuthenticationToken;
+import org.jsecurity.session.Session;
+import org.jsecurity.subject.PrincipalCollection;
+import org.jsecurity.subject.Subject;
+
+import java.net.InetAddress;
+
+/**
+ * TODO - Class JavaDoc
+ *
+ * @author Les Hazlewood
+ * @since 1.0
+ */
+public interface SubjectFactory {
+
+    Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing);
+
+    Subject createSubject(PrincipalCollection principals, Session existing,
+                          boolean authenticated, InetAddress originatingHost);
+
+}
diff --git a/core/src/org/jsecurity/mgt/ThreadContextSubjectBinder.java b/core/src/org/jsecurity/mgt/ThreadContextSubjectBinder.java
new file mode 100644
index 0000000..1fd310a
--- /dev/null
+++ b/core/src/org/jsecurity/mgt/ThreadContextSubjectBinder.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jsecurity.mgt;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jsecurity.subject.Subject;
+import org.jsecurity.util.ThreadContext;
+
+/**
+ * TODO - Class JavaDoc
+ *
+ * @author Les Hazlewood
+ * @since 1.0
+ */
+public class ThreadContextSubjectBinder implements SubjectBinder {
+
+    private static final Log log = LogFactory.getLog(ThreadContextSubjectBinder.class);
+
+    public Subject getSubject() {
+        return ThreadContext.getSubject();
+    }
+
+    public void bind(Subject subject) {
+        if (log.isTraceEnabled()) {
+            log.trace("Binding Subject [" + subject + "] to a thread local...");
+        }
+        ThreadContext.bind(subject);
+    }
+
+    public void unbind(Subject subject) {
+        ThreadContext.unbindSubject();
+    }
+}
diff --git a/web/src/org/jsecurity/web/DefaultWebSecurityManager.java b/web/src/org/jsecurity/web/DefaultWebSecurityManager.java
index 1831619..f8731b7 100644
--- a/web/src/org/jsecurity/web/DefaultWebSecurityManager.java
+++ b/web/src/org/jsecurity/web/DefaultWebSecurityManager.java
@@ -22,18 +22,12 @@
 import org.apache.commons.logging.LogFactory;

 import org.jsecurity.mgt.DefaultSecurityManager;

 import org.jsecurity.realm.Realm;

-import org.jsecurity.session.Session;

 import org.jsecurity.session.mgt.SessionManager;

-import org.jsecurity.subject.PrincipalCollection;

-import org.jsecurity.subject.Subject;

 import org.jsecurity.util.LifecycleUtils;

 import org.jsecurity.web.session.DefaultWebSessionManager;

 import org.jsecurity.web.session.ServletContainerSessionManager;

 import org.jsecurity.web.session.WebSessionManager;

 

-import javax.servlet.ServletRequest;

-import javax.servlet.ServletResponse;

-import java.net.InetAddress;

 import java.util.Collection;

 

 /**

@@ -66,6 +60,7 @@
 

     public DefaultWebSecurityManager() {

         setRememberMeManager(new WebRememberMeManager());

+        setSubjectFactory(new WebSubjectFactory(this, (WebSessionManager) getSessionManager()));

     }

 

     public DefaultWebSecurityManager(Realm singleRealm) {

@@ -145,6 +140,7 @@
             LifecycleUtils.destroy(getSessionManager());

             SessionManager sm = createSessionManager();

             setSessionManager(sm);

+            setSubjectFactory(new WebSubjectFactory(this, (WebSessionManager) getSessionManager()));

         }

     }

 

@@ -165,99 +161,4 @@
             return new DefaultWebSessionManager();

         }

     }

-

-    protected PrincipalCollection getPrincipals(Session session) {

-        PrincipalCollection principals = null;

-        if (session != null) {

-            principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);

-        }

-        return principals;

-    }

-

-    protected PrincipalCollection getPrincipals(Session existing, ServletRequest servletRequest, ServletResponse servletResponse) {

-        PrincipalCollection principals = getPrincipals(existing);

-        if (principals == null) {

-            //check remember me:

-            principals = getRememberedIdentity();

-            if (principals != null && existing != null) {

-                existing.setAttribute(PRINCIPALS_SESSION_KEY, principals);

-            }

-        }

-        return principals;

-    }

-

-    protected boolean isAuthenticated(Session session) {

-        Boolean value = null;

-        if (session != null) {

-            value = (Boolean) session.getAttribute(AUTHENTICATED_SESSION_KEY);

-        }

-        return value != null && value;

-    }

-

-    protected boolean isAuthenticated(Session existing, ServletRequest servletRequest, ServletResponse servletResponse) {

-        return isAuthenticated(existing);

-    }

-

-    public Subject createSubject() {

-        ServletRequest request = WebUtils.getRequiredServletRequest();

-        ServletResponse response = WebUtils.getRequiredServletResponse();

-        return createSubject(request, response);

-    }

-

-    public Subject createSubject(ServletRequest request, ServletResponse response) {

-        Session session = ((WebSessionManager) getSessionManager()).getSession(request, response);

-        if (session == null) {

-            if (log.isTraceEnabled()) {

-                log.trace("No session found for the incoming request.  The Subject instance created for " +

-                        "the incoming request will not have an associated Session.");

-            }

-        }

-        return createSubject(session, request, response);

-    }

-

-    public Subject createSubject(Session existing, ServletRequest request, ServletResponse response) {

-        PrincipalCollection principals = getPrincipals(existing, request, response);

-        boolean authenticated = isAuthenticated(existing, request, response);

-        return createSubject(principals, authenticated, existing, request, response);

-    }

-

-    protected Subject createSubject(PrincipalCollection principals,

-                                    boolean authenticated,

-                                    Session existing,

-                                    ServletRequest request,

-                                    ServletResponse response) {

-        InetAddress inetAddress = WebUtils.getInetAddress(request);

-        return createSubject(principals, existing, authenticated, inetAddress);

-    }

-

-    protected void bind(Subject subject) {

-        super.bind(subject);

-        ServletRequest request = WebUtils.getRequiredServletRequest();

-        ServletResponse response = WebUtils.getRequiredServletResponse();

-        bind(subject, request, response);

-    }

-

-    protected void bind(Subject subject, ServletRequest request, ServletResponse response) {

-

-        PrincipalCollection principals = subject.getPrincipals();

-        if (principals != null && !principals.isEmpty()) {

-            Session session = subject.getSession();

-            session.setAttribute(PRINCIPALS_SESSION_KEY, principals);

-        } else {

-            Session session = subject.getSession(false);

-            if (session != null) {

-                session.removeAttribute(PRINCIPALS_SESSION_KEY);

-            }

-        }

-

-        if (subject.isAuthenticated()) {

-            Session session = subject.getSession();

-            session.setAttribute(AUTHENTICATED_SESSION_KEY, subject.isAuthenticated());

-        } else {

-            Session session = subject.getSession(false);

-            if (session != null) {

-                session.removeAttribute(AUTHENTICATED_SESSION_KEY);

-            }

-        }

-    }

 }

diff --git a/web/src/org/jsecurity/web/WebSubjectFactory.java b/web/src/org/jsecurity/web/WebSubjectFactory.java
new file mode 100644
index 0000000..6952e3d
--- /dev/null
+++ b/web/src/org/jsecurity/web/WebSubjectFactory.java
@@ -0,0 +1,118 @@
+/*
+ * 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.jsecurity.web;
+
+import org.jsecurity.mgt.DefaultSubjectFactory;
+import org.jsecurity.mgt.SecurityManager;
+import org.jsecurity.mgt.SessionSubjectBinder;
+import org.jsecurity.session.Session;
+import org.jsecurity.subject.PrincipalCollection;
+import org.jsecurity.subject.Subject;
+import org.jsecurity.web.session.WebSessionManager;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.net.InetAddress;
+
+/**
+ * @author Les Hazlewood
+ * @since 1.0
+ */
+public class WebSubjectFactory extends DefaultSubjectFactory {
+
+    public static final String PRINCIPALS_SESSION_KEY = SessionSubjectBinder.PRINCIPALS_SESSION_KEY;
+    public static final String AUTHENTICATED_SESSION_KEY = SessionSubjectBinder.AUTHENTICATED_SESSION_KEY;
+
+    WebSessionManager webSessionManager;
+
+    public WebSubjectFactory() {
+    }
+
+    public WebSubjectFactory(SecurityManager securityManager) {
+        super(securityManager);
+    }
+
+    public WebSubjectFactory(SecurityManager securityManager, WebSessionManager webSessionManager) {
+        super(securityManager);
+        setWebSessionManager(webSessionManager);
+    }
+
+    public WebSessionManager getWebSessionManager() {
+        return webSessionManager;
+    }
+
+    public void setWebSessionManager(WebSessionManager webSessionManager) {
+        this.webSessionManager = webSessionManager;
+    }
+
+    protected PrincipalCollection getPrincipals(Session existing) {
+        PrincipalCollection principals = null;
+        if (existing != null) {
+            principals = (PrincipalCollection) existing.getAttribute(PRINCIPALS_SESSION_KEY);
+        }
+//        if (principals == null) {
+//            //check remember me:
+//            principals = getRememberedIdentity();
+//            if (principals != null && existing != null) {
+//                existing.setAttribute(PRINCIPALS_SESSION_KEY, principals);
+//            }
+//        }
+        return principals;
+    }
+
+    protected boolean isAuthenticated(Session session) {
+        Boolean value = null;
+        if (session != null) {
+            value = (Boolean) session.getAttribute(AUTHENTICATED_SESSION_KEY);
+        }
+        return value != null && value;
+    }
+
+    protected Session getWebSession() {
+        ServletRequest request = WebUtils.getRequiredServletRequest();
+        ServletResponse response = WebUtils.getRequiredServletResponse();
+        return getWebSessionManager().getSession(request, response);
+    }
+
+    @Override
+    public Subject createSubject(PrincipalCollection principals, Session existing, boolean authenticated, InetAddress inetAddress) {
+        Session session = existing;
+        if (session == null) {
+            session = getWebSession();
+        }
+
+        PrincipalCollection pc = principals;
+        if (pc == null) {
+            pc = getPrincipals(session);
+        }
+
+        boolean authc = authenticated;
+        if (!authc) {
+            //check session to be sure:
+            authc = isAuthenticated(session);
+        }
+
+        InetAddress inet = inetAddress;
+        if (inet == null) {
+            inet = WebUtils.getInetAddress(WebUtils.getRequiredServletRequest());
+        }
+
+        return super.createSubject(pc, session, authc, inet);
+    }
+}