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