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 */
019package org.apache.shiro.subject.support;
020
021import org.apache.shiro.SecurityUtils;
022import org.apache.shiro.UnavailableSecurityManagerException;
023import org.apache.shiro.authc.AuthenticationInfo;
024import org.apache.shiro.authc.AuthenticationToken;
025import org.apache.shiro.authc.HostAuthenticationToken;
026import org.apache.shiro.mgt.SecurityManager;
027import org.apache.shiro.session.Session;
028import org.apache.shiro.subject.PrincipalCollection;
029import org.apache.shiro.subject.Subject;
030import org.apache.shiro.subject.SubjectContext;
031import org.apache.shiro.util.CollectionUtils;
032import org.apache.shiro.util.MapContext;
033import org.apache.shiro.util.StringUtils;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036
037import 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 */
048public 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}