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     * @author Les Hazlewood
047     * @since 1.0
048     */
049    public class DefaultSubjectContext extends MapContext implements SubjectContext {
050    
051        private static final String SECURITY_MANAGER = DefaultSubjectContext.class.getName() + ".SECURITY_MANAGER";
052    
053        private static final String SESSION_ID = DefaultSubjectContext.class.getName() + ".SESSION_ID";
054    
055        private static final String AUTHENTICATION_TOKEN = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_TOKEN";
056    
057        private static final String AUTHENTICATION_INFO = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_INFO";
058    
059        private static final String SUBJECT = DefaultSubjectContext.class.getName() + ".SUBJECT";
060    
061        private static final String PRINCIPALS = DefaultSubjectContext.class.getName() + ".PRINCIPALS";
062    
063        private static final String SESSION = DefaultSubjectContext.class.getName() + ".SESSION";
064    
065        private static final String AUTHENTICATED = DefaultSubjectContext.class.getName() + ".AUTHENTICATED";
066    
067        private static final String HOST = DefaultSubjectContext.class.getName() + ".HOST";
068    
069        /**
070         * The session key that is used to store subject principals.
071         */
072        public static final String PRINCIPALS_SESSION_KEY = DefaultSubjectContext.class.getName() + "_PRINCIPALS_SESSION_KEY";
073    
074        /**
075         * The session key that is used to store whether or not the user is authenticated.
076         */
077        public static final String AUTHENTICATED_SESSION_KEY = DefaultSubjectContext.class.getName() + "_AUTHENTICATED_SESSION_KEY";
078    
079        private static final transient Logger log = LoggerFactory.getLogger(DefaultSubjectContext.class);
080    
081        public DefaultSubjectContext() {
082            super();
083        }
084    
085        public DefaultSubjectContext(SubjectContext ctx) {
086            super(ctx);
087        }
088    
089        public SecurityManager getSecurityManager() {
090            return getTypedValue(SECURITY_MANAGER, SecurityManager.class);
091        }
092    
093        public void setSecurityManager(SecurityManager securityManager) {
094            nullSafePut(SECURITY_MANAGER, securityManager);
095        }
096    
097        public SecurityManager resolveSecurityManager() {
098            SecurityManager securityManager = getSecurityManager();
099            if (securityManager == null) {
100                if (log.isDebugEnabled()) {
101                    log.debug("No SecurityManager available in subject context map.  " +
102                            "Falling back to SecurityUtils.getSecurityManager() lookup.");
103                }
104                try {
105                    securityManager = SecurityUtils.getSecurityManager();
106                } catch (UnavailableSecurityManagerException e) {
107                    if (log.isDebugEnabled()) {
108                        log.debug("No SecurityManager available via SecurityUtils.  Heuristics exhausted.", e);
109                    }
110                }
111            }
112            return securityManager;
113        }
114    
115        public Serializable getSessionId() {
116            return getTypedValue(SESSION_ID, Serializable.class);
117        }
118    
119        public void setSessionId(Serializable sessionId) {
120            nullSafePut(SESSION_ID, sessionId);
121        }
122    
123        public Subject getSubject() {
124            return getTypedValue(SUBJECT, Subject.class);
125        }
126    
127        public void setSubject(Subject subject) {
128            nullSafePut(SUBJECT, subject);
129        }
130    
131        public PrincipalCollection getPrincipals() {
132            return getTypedValue(PRINCIPALS, PrincipalCollection.class);
133        }
134    
135        public void setPrincipals(PrincipalCollection principals) {
136            if (!CollectionUtils.isEmpty(principals)) {
137                put(PRINCIPALS, principals);
138            }
139        }
140    
141        public PrincipalCollection resolvePrincipals() {
142            PrincipalCollection principals = getPrincipals();
143    
144            if (CollectionUtils.isEmpty(principals)) {
145                //check to see if they were just authenticated:
146                AuthenticationInfo info = getAuthenticationInfo();
147                if (info != null) {
148                    principals = info.getPrincipals();
149                }
150            }
151    
152            if (CollectionUtils.isEmpty(principals)) {
153                Subject subject = getSubject();
154                if (subject != null) {
155                    principals = subject.getPrincipals();
156                }
157            }
158    
159            if (CollectionUtils.isEmpty(principals)) {
160                //try the session:
161                Session session = resolveSession();
162                if (session != null) {
163                    principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);
164                }
165            }
166    
167            return principals;
168        }
169    
170    
171        public Session getSession() {
172            return getTypedValue(SESSION, Session.class);
173        }
174    
175        public void setSession(Session session) {
176            nullSafePut(SESSION, session);
177        }
178    
179        public Session resolveSession() {
180            Session session = getSession();
181            if (session == null) {
182                //try the Subject if it exists:
183                Subject existingSubject = getSubject();
184                if (existingSubject != null) {
185                    session = existingSubject.getSession(false);
186                }
187            }
188            return session;
189        }
190    
191        public boolean isAuthenticated() {
192            Boolean authc = getTypedValue(AUTHENTICATED, Boolean.class);
193            return authc != null && authc;
194        }
195    
196        public void setAuthenticated(boolean authc) {
197            put(AUTHENTICATED, authc);
198        }
199    
200        public boolean resolveAuthenticated() {
201            Boolean authc = getTypedValue(AUTHENTICATED, Boolean.class);
202            if (authc == null) {
203                //see if there is an AuthenticationInfo object.  If so, the very presence of one indicates a successful
204                //authentication attempt:
205                AuthenticationInfo info = getAuthenticationInfo();
206                authc = info != null;
207            }
208            if (!authc) {
209                //fall back to a session check:
210                Session session = resolveSession();
211                if (session != null) {
212                    Boolean sessionAuthc = (Boolean) session.getAttribute(AUTHENTICATED_SESSION_KEY);
213                    authc = sessionAuthc != null && sessionAuthc;
214                }
215            }
216    
217            return authc;
218        }
219    
220        public AuthenticationInfo getAuthenticationInfo() {
221            return getTypedValue(AUTHENTICATION_INFO, AuthenticationInfo.class);
222        }
223    
224        public void setAuthenticationInfo(AuthenticationInfo info) {
225            nullSafePut(AUTHENTICATION_INFO, info);
226        }
227    
228        public AuthenticationToken getAuthenticationToken() {
229            return getTypedValue(AUTHENTICATION_TOKEN, AuthenticationToken.class);
230        }
231    
232        public void setAuthenticationToken(AuthenticationToken token) {
233            nullSafePut(AUTHENTICATION_TOKEN, token);
234        }
235    
236        public String getHost() {
237            return getTypedValue(HOST, String.class);
238        }
239    
240        public void setHost(String host) {
241            if (StringUtils.hasText(host)) {
242                put(HOST, host);
243            }
244        }
245    
246        public String resolveHost() {
247            String host = getHost();
248    
249            if (host == null) {
250                //check to see if there is an AuthenticationToken from which to retrieve it:
251                AuthenticationToken token = getAuthenticationToken();
252                if (token instanceof HostAuthenticationToken) {
253                    host = ((HostAuthenticationToken) token).getHost();
254                }
255            }
256    
257            if (host == null) {
258                Session session = resolveSession();
259                if (session != null) {
260                    host = session.getHost();
261                }
262            }
263    
264            return host;
265        }
266    }