001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.shiro.subject.support;
020    
021    import org.apache.shiro.SecurityUtils;
022    import org.apache.shiro.UnavailableSecurityManagerException;
023    import org.apache.shiro.authc.AuthenticationInfo;
024    import org.apache.shiro.authc.AuthenticationToken;
025    import org.apache.shiro.authc.HostAuthenticationToken;
026    import org.apache.shiro.mgt.SecurityManager;
027    import org.apache.shiro.session.Session;
028    import org.apache.shiro.subject.PrincipalCollection;
029    import org.apache.shiro.subject.Subject;
030    import org.apache.shiro.subject.SubjectContext;
031    import org.apache.shiro.util.CollectionUtils;
032    import org.apache.shiro.util.MapContext;
033    import org.apache.shiro.util.StringUtils;
034    import org.slf4j.Logger;
035    import org.slf4j.LoggerFactory;
036    
037    import java.io.Serializable;
038    
039    /**
040     * Default implementation of the {@link SubjectContext} interface.  Note that the getters and setters are not
041     * simple pass-through methods to an underlying attribute;  the getters will employ numerous heuristics to acquire
042     * their data attribute as best as possible (for example, if {@link #getPrincipals} is invoked, if the principals aren't
043     * in the backing map, it might check to see if there is a subject or session in the map and attempt to acquire the
044     * principals from those objects).
045     *
046     * @since 1.0
047     */
048    public class DefaultSubjectContext extends MapContext implements SubjectContext {
049    
050        private static final String SECURITY_MANAGER = DefaultSubjectContext.class.getName() + ".SECURITY_MANAGER";
051    
052        private static final String SESSION_ID = DefaultSubjectContext.class.getName() + ".SESSION_ID";
053    
054        private static final String AUTHENTICATION_TOKEN = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_TOKEN";
055    
056        private static final String AUTHENTICATION_INFO = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_INFO";
057    
058        private static final String SUBJECT = DefaultSubjectContext.class.getName() + ".SUBJECT";
059    
060        private static final String PRINCIPALS = DefaultSubjectContext.class.getName() + ".PRINCIPALS";
061    
062        private static final String SESSION = DefaultSubjectContext.class.getName() + ".SESSION";
063    
064        private static final String AUTHENTICATED = DefaultSubjectContext.class.getName() + ".AUTHENTICATED";
065    
066        private static final String HOST = DefaultSubjectContext.class.getName() + ".HOST";
067    
068        public static final String SESSION_CREATION_ENABLED = DefaultSubjectContext.class.getName() + ".SESSION_CREATION_ENABLED";
069    
070        /**
071         * The session key that is used to store subject principals.
072         */
073        public static final String PRINCIPALS_SESSION_KEY = DefaultSubjectContext.class.getName() + "_PRINCIPALS_SESSION_KEY";
074    
075        /**
076         * The session key that is used to store whether or not the user is authenticated.
077         */
078        public static final String AUTHENTICATED_SESSION_KEY = DefaultSubjectContext.class.getName() + "_AUTHENTICATED_SESSION_KEY";
079    
080        private static final transient Logger log = LoggerFactory.getLogger(DefaultSubjectContext.class);
081    
082        public DefaultSubjectContext() {
083            super();
084        }
085    
086        public DefaultSubjectContext(SubjectContext ctx) {
087            super(ctx);
088        }
089    
090        public SecurityManager getSecurityManager() {
091            return getTypedValue(SECURITY_MANAGER, SecurityManager.class);
092        }
093    
094        public void setSecurityManager(SecurityManager securityManager) {
095            nullSafePut(SECURITY_MANAGER, securityManager);
096        }
097    
098        public SecurityManager resolveSecurityManager() {
099            SecurityManager securityManager = getSecurityManager();
100            if (securityManager == null) {
101                if (log.isDebugEnabled()) {
102                    log.debug("No SecurityManager available in subject context map.  " +
103                            "Falling back to SecurityUtils.getSecurityManager() lookup.");
104                }
105                try {
106                    securityManager = SecurityUtils.getSecurityManager();
107                } catch (UnavailableSecurityManagerException e) {
108                    if (log.isDebugEnabled()) {
109                        log.debug("No SecurityManager available via SecurityUtils.  Heuristics exhausted.", e);
110                    }
111                }
112            }
113            return securityManager;
114        }
115    
116        public Serializable getSessionId() {
117            return getTypedValue(SESSION_ID, Serializable.class);
118        }
119    
120        public void setSessionId(Serializable sessionId) {
121            nullSafePut(SESSION_ID, sessionId);
122        }
123    
124        public Subject getSubject() {
125            return getTypedValue(SUBJECT, Subject.class);
126        }
127    
128        public void setSubject(Subject subject) {
129            nullSafePut(SUBJECT, subject);
130        }
131    
132        public PrincipalCollection getPrincipals() {
133            return getTypedValue(PRINCIPALS, PrincipalCollection.class);
134        }
135    
136        public void setPrincipals(PrincipalCollection principals) {
137            if (!CollectionUtils.isEmpty(principals)) {
138                put(PRINCIPALS, principals);
139            }
140        }
141    
142        public PrincipalCollection resolvePrincipals() {
143            PrincipalCollection principals = getPrincipals();
144    
145            if (CollectionUtils.isEmpty(principals)) {
146                //check to see if they were just authenticated:
147                AuthenticationInfo info = getAuthenticationInfo();
148                if (info != null) {
149                    principals = info.getPrincipals();
150                }
151            }
152    
153            if (CollectionUtils.isEmpty(principals)) {
154                Subject subject = getSubject();
155                if (subject != null) {
156                    principals = subject.getPrincipals();
157                }
158            }
159    
160            if (CollectionUtils.isEmpty(principals)) {
161                //try the session:
162                Session session = resolveSession();
163                if (session != null) {
164                    principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);
165                }
166            }
167    
168            return principals;
169        }
170    
171    
172        public Session getSession() {
173            return getTypedValue(SESSION, Session.class);
174        }
175    
176        public void setSession(Session session) {
177            nullSafePut(SESSION, session);
178        }
179    
180        public Session resolveSession() {
181            Session session = getSession();
182            if (session == null) {
183                //try the Subject if it exists:
184                Subject existingSubject = getSubject();
185                if (existingSubject != null) {
186                    session = existingSubject.getSession(false);
187                }
188            }
189            return session;
190        }
191    
192        public boolean isSessionCreationEnabled() {
193            Boolean val = getTypedValue(SESSION_CREATION_ENABLED, Boolean.class);
194            return val == null || val;
195        }
196    
197        public void setSessionCreationEnabled(boolean enabled) {
198            nullSafePut(SESSION_CREATION_ENABLED, enabled);
199        }
200    
201        public boolean isAuthenticated() {
202            Boolean authc = getTypedValue(AUTHENTICATED, Boolean.class);
203            return authc != null && authc;
204        }
205    
206        public void setAuthenticated(boolean authc) {
207            put(AUTHENTICATED, authc);
208        }
209    
210        public boolean resolveAuthenticated() {
211            Boolean authc = getTypedValue(AUTHENTICATED, Boolean.class);
212            if (authc == null) {
213                //see if there is an AuthenticationInfo object.  If so, the very presence of one indicates a successful
214                //authentication attempt:
215                AuthenticationInfo info = getAuthenticationInfo();
216                authc = info != null;
217            }
218            if (!authc) {
219                //fall back to a session check:
220                Session session = resolveSession();
221                if (session != null) {
222                    Boolean sessionAuthc = (Boolean) session.getAttribute(AUTHENTICATED_SESSION_KEY);
223                    authc = sessionAuthc != null && sessionAuthc;
224                }
225            }
226    
227            return authc;
228        }
229    
230        public AuthenticationInfo getAuthenticationInfo() {
231            return getTypedValue(AUTHENTICATION_INFO, AuthenticationInfo.class);
232        }
233    
234        public void setAuthenticationInfo(AuthenticationInfo info) {
235            nullSafePut(AUTHENTICATION_INFO, info);
236        }
237    
238        public AuthenticationToken getAuthenticationToken() {
239            return getTypedValue(AUTHENTICATION_TOKEN, AuthenticationToken.class);
240        }
241    
242        public void setAuthenticationToken(AuthenticationToken token) {
243            nullSafePut(AUTHENTICATION_TOKEN, token);
244        }
245    
246        public String getHost() {
247            return getTypedValue(HOST, String.class);
248        }
249    
250        public void setHost(String host) {
251            if (StringUtils.hasText(host)) {
252                put(HOST, host);
253            }
254        }
255    
256        public String resolveHost() {
257            String host = getHost();
258    
259            if (host == null) {
260                //check to see if there is an AuthenticationToken from which to retrieve it:
261                AuthenticationToken token = getAuthenticationToken();
262                if (token instanceof HostAuthenticationToken) {
263                    host = ((HostAuthenticationToken) token).getHost();
264                }
265            }
266    
267            if (host == null) {
268                Session session = resolveSession();
269                if (session != null) {
270                    host = session.getHost();
271                }
272            }
273    
274            return host;
275        }
276    }