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.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    private static final String SECURITY_MANAGER = DefaultSubjectContext.class.getName() + ".SECURITY_MANAGER";
050
051    private static final String SESSION_ID = DefaultSubjectContext.class.getName() + ".SESSION_ID";
052
053    private static final String AUTHENTICATION_TOKEN = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_TOKEN";
054
055    private static final String AUTHENTICATION_INFO = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_INFO";
056
057    private static final String SUBJECT = DefaultSubjectContext.class.getName() + ".SUBJECT";
058
059    private static final String PRINCIPALS = DefaultSubjectContext.class.getName() + ".PRINCIPALS";
060
061    private static final String SESSION = DefaultSubjectContext.class.getName() + ".SESSION";
062
063    private static final String AUTHENTICATED = DefaultSubjectContext.class.getName() + ".AUTHENTICATED";
064
065    private static final String HOST = DefaultSubjectContext.class.getName() + ".HOST";
066
067    public static final String SESSION_CREATION_ENABLED = DefaultSubjectContext.class.getName() + ".SESSION_CREATION_ENABLED";
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    private static boolean isEmpty(PrincipalCollection pc) {
136        return pc == null || pc.isEmpty();
137    }
138
139    public void setPrincipals(PrincipalCollection principals) {
140        if (!isEmpty(principals)) {
141            put(PRINCIPALS, principals);
142        }
143    }
144
145    public PrincipalCollection resolvePrincipals() {
146        PrincipalCollection principals = getPrincipals();
147
148        if (isEmpty(principals)) {
149            //check to see if they were just authenticated:
150            AuthenticationInfo info = getAuthenticationInfo();
151            if (info != null) {
152                principals = info.getPrincipals();
153            }
154        }
155
156        if (isEmpty(principals)) {
157            Subject subject = getSubject();
158            if (subject != null) {
159                principals = subject.getPrincipals();
160            }
161        }
162
163        if (isEmpty(principals)) {
164            //try the session:
165            Session session = resolveSession();
166            if (session != null) {
167                principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);
168            }
169        }
170
171        return principals;
172    }
173
174
175    public Session getSession() {
176        return getTypedValue(SESSION, Session.class);
177    }
178
179    public void setSession(Session session) {
180        nullSafePut(SESSION, session);
181    }
182
183    public Session resolveSession() {
184        Session session = getSession();
185        if (session == null) {
186            //try the Subject if it exists:
187            Subject existingSubject = getSubject();
188            if (existingSubject != null) {
189                session = existingSubject.getSession(false);
190            }
191        }
192        return session;
193    }
194
195    public boolean isSessionCreationEnabled() {
196        Boolean val = getTypedValue(SESSION_CREATION_ENABLED, Boolean.class);
197        return val == null || val;
198    }
199
200    public void setSessionCreationEnabled(boolean enabled) {
201        nullSafePut(SESSION_CREATION_ENABLED, enabled);
202    }
203
204    public boolean isAuthenticated() {
205        Boolean authc = getTypedValue(AUTHENTICATED, Boolean.class);
206        return authc != null && authc;
207    }
208
209    public void setAuthenticated(boolean authc) {
210        put(AUTHENTICATED, authc);
211    }
212
213    public boolean resolveAuthenticated() {
214        Boolean authc = getTypedValue(AUTHENTICATED, Boolean.class);
215        if (authc == null) {
216            //see if there is an AuthenticationInfo object.  If so, the very presence of one indicates a successful
217            //authentication attempt:
218            AuthenticationInfo info = getAuthenticationInfo();
219            authc = info != null;
220        }
221        if (!authc) {
222            //fall back to a session check:
223            Session session = resolveSession();
224            if (session != null) {
225                Boolean sessionAuthc = (Boolean) session.getAttribute(AUTHENTICATED_SESSION_KEY);
226                authc = sessionAuthc != null && sessionAuthc;
227            }
228        }
229
230        return authc;
231    }
232
233    public AuthenticationInfo getAuthenticationInfo() {
234        return getTypedValue(AUTHENTICATION_INFO, AuthenticationInfo.class);
235    }
236
237    public void setAuthenticationInfo(AuthenticationInfo info) {
238        nullSafePut(AUTHENTICATION_INFO, info);
239    }
240
241    public AuthenticationToken getAuthenticationToken() {
242        return getTypedValue(AUTHENTICATION_TOKEN, AuthenticationToken.class);
243    }
244
245    public void setAuthenticationToken(AuthenticationToken token) {
246        nullSafePut(AUTHENTICATION_TOKEN, token);
247    }
248
249    public String getHost() {
250        return getTypedValue(HOST, String.class);
251    }
252
253    public void setHost(String host) {
254        if (StringUtils.hasText(host)) {
255            put(HOST, host);
256        }
257    }
258
259    public String resolveHost() {
260        String host = getHost();
261
262        if (host == null) {
263            //check to see if there is an AuthenticationToken from which to retrieve it:
264            AuthenticationToken token = getAuthenticationToken();
265            if (token instanceof HostAuthenticationToken) {
266                host = ((HostAuthenticationToken) token).getHost();
267            }
268        }
269
270        if (host == null) {
271            Session session = resolveSession();
272            if (session != null) {
273                host = session.getHost();
274            }
275        }
276
277        return host;
278    }
279}