1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 module hunt.shiro.subject.support.DefaultSubjectContext;
20 
21 import hunt.shiro.Exceptions;
22 import hunt.shiro.SecurityUtils;
23 import hunt.shiro.authc.AuthenticationInfo;
24 import hunt.shiro.authc.AuthenticationToken;
25 import hunt.shiro.authc.HostAuthenticationToken;
26 import hunt.shiro.mgt.SecurityManager;
27 import hunt.shiro.session.Session;
28 import hunt.shiro.subject.PrincipalCollection;
29 import hunt.shiro.subject.Subject;
30 import hunt.shiro.subject.SubjectContext;
31 import hunt.shiro.util.MapContext;
32 // // import hunt.shiro.util.StringUtils;
33 import hunt.logging.Logger;
34 
35 import hunt.Boolean;
36 import hunt.collection.Map;
37 import hunt.String;
38 import hunt.util.Common;
39 
40 import std.array;
41 import std.traits;
42 
43 /**
44  * Default implementation of the {@link SubjectContext} interface.  Note that the getters and setters are not
45  * simple pass-through methods to an underlying attribute;  the getters will employ numerous heuristics to acquire
46  * their data attribute as best as possible (for example, if {@link #getPrincipals} is invoked, if the principals aren't
47  * in the backing map, it might check to see if there is a subject or session in the map and attempt to acquire the
48  * principals from those objects).
49  *
50  */
51 class DefaultSubjectContext : MapContext, SubjectContext {
52 
53     private enum string SECURITY_MANAGER = fullyQualifiedName!(DefaultSubjectContext) ~ ".SECURITY_MANAGER";
54 
55     private enum string SESSION_ID = fullyQualifiedName!(DefaultSubjectContext) ~ ".SESSION_ID";
56 
57     private enum string AUTHENTICATION_TOKEN = fullyQualifiedName!(DefaultSubjectContext) ~ ".AUTHENTICATION_TOKEN";
58 
59     private enum string AUTHENTICATION_INFO = fullyQualifiedName!(DefaultSubjectContext) ~ ".AUTHENTICATION_INFO";
60 
61     private enum string SUBJECT = fullyQualifiedName!(DefaultSubjectContext) ~ ".SUBJECT";
62 
63     private enum string PRINCIPALS = fullyQualifiedName!(DefaultSubjectContext) ~ ".PRINCIPALS";
64 
65     private enum string SESSION = fullyQualifiedName!(DefaultSubjectContext) ~ ".SESSION";
66 
67     private enum string AUTHENTICATED = fullyQualifiedName!(DefaultSubjectContext) ~ ".AUTHENTICATED";
68 
69     private enum string HOST = fullyQualifiedName!(DefaultSubjectContext) ~ ".HOST";
70 
71     enum string SESSION_CREATION_ENABLED = fullyQualifiedName!(DefaultSubjectContext) ~ ".SESSION_CREATION_ENABLED";
72 
73     /**
74      * The session key that is used to store subject principals.
75      */
76     enum string PRINCIPALS_SESSION_KEY = fullyQualifiedName!(DefaultSubjectContext) ~ "_PRINCIPALS_SESSION_KEY";
77 
78     /**
79      * The session key that is used to store whether or not the user is authenticated.
80      */
81     enum string AUTHENTICATED_SESSION_KEY = fullyQualifiedName!(DefaultSubjectContext) ~ "_AUTHENTICATED_SESSION_KEY";
82 
83 
84 
85     this() {
86         super();
87     }
88 
89     this(SubjectContext ctx) {
90         super(cast(Map!(string, Object))ctx);
91     }
92 
93     SecurityManager getSecurityManager() {
94         return getTypedValue!SecurityManager(SECURITY_MANAGER);
95     }
96 
97     void setSecurityManager(SecurityManager securityManager) {
98         nullSafePut(SECURITY_MANAGER, cast(Object)securityManager);
99     }
100 
101     SecurityManager resolveSecurityManager() {
102         SecurityManager securityManager = getSecurityManager();
103         if (securityManager is null) {
104             version(HUNT_AUTH_DEBUG) {
105                 warningf("No SecurityManager available in subject context map.  " ~
106                         "Falling back to SecurityUtils.getSecurityManager() lookup.");
107             }
108             // try {
109             //     securityManager = SecurityUtils.getSecurityManager();
110             // } catch (UnavailableSecurityManagerException e) {
111             //     version(HUNT_AUTH_DEBUG) {
112             //         warningf("No SecurityManager available via SecurityUtils." ~ 
113             //             " Heuristics exhausted. The reason is: %s", e.msg);
114             //     } 
115             //     version(HUNT_SHIRO_DEBUG) {
116             //         warning(e);
117             //     }
118             // }
119         }
120         return securityManager;
121     }
122 
123     string getSessionId() {
124         String s = getTypedValue!String(SESSION_ID);
125         if(s !is null)
126             return getTypedValue!String(SESSION_ID).value;
127         else
128             return null;
129     }
130 
131     void setSessionId(string sessionId) {
132         nullSafePut(SESSION_ID, new String(sessionId));
133     }
134 
135     Subject getSubject() {
136         return getTypedValue!Subject(SUBJECT);
137     }
138 
139      void setSubject(Subject subject) {
140         nullSafePut(SUBJECT, cast(Object)subject);
141     }
142 
143      PrincipalCollection getPrincipals() {
144         return getTypedValue!PrincipalCollection(PRINCIPALS);
145     }
146 
147     private static bool isEmpty(PrincipalCollection pc) {
148         return pc  is null || pc.isEmpty();
149     }
150 
151     void setPrincipals(PrincipalCollection principals) {
152         if (!isEmpty(principals)) {
153             put(PRINCIPALS, cast(Object)principals);
154         }
155     }
156 
157     PrincipalCollection resolvePrincipals() {
158         PrincipalCollection principals = getPrincipals();
159 
160         if (isEmpty(principals)) {
161             //check to see if they were just authenticated:
162             AuthenticationInfo info = getAuthenticationInfo();
163             if (info !is null) {
164                 principals = info.getPrincipals();
165             }
166         }
167 
168         if (isEmpty(principals)) {
169             Subject subject = getSubject();
170             if (subject !is null) {
171                 principals = subject.getPrincipals();
172             }
173         }
174 
175         if (isEmpty(principals)) {
176             //try the session:
177             Session session = resolveSession();
178             if (session !is null) {
179                 principals = cast(PrincipalCollection) session.getAttribute(new String(PRINCIPALS_SESSION_KEY));
180             }
181         }
182 
183         return principals;
184     }
185 
186 
187     Session getSession() {
188         return getTypedValue!Session(SESSION);
189     }
190 
191     void setSession(Session session) {
192         nullSafePut(SESSION, cast(Object)session);
193     }
194 
195      Session resolveSession() {
196         Session session = getSession();
197         if (session  is null) {
198             //try the Subject if it exists:
199             Subject existingSubject = getSubject();
200             if (existingSubject !is null) {
201                 session = existingSubject.getSession(false);
202             }
203         }
204         return session;
205     }
206 
207     bool isSessionCreationEnabled() {
208         Boolean val = getTypedValue!(Boolean)(SESSION_CREATION_ENABLED);
209         return val is null || val.value;
210     }
211 
212     void setSessionCreationEnabled(bool enabled) {
213         nullSafePut(SESSION_CREATION_ENABLED, new Boolean(enabled));
214     }
215 
216     bool isAuthenticated() {
217         Boolean authc = getTypedValue!(Boolean)(AUTHENTICATED);
218         return authc !is null && authc.value;
219     }
220 
221     void setAuthenticated(bool authc) {
222         put(AUTHENTICATED, new Boolean(authc));
223     }
224 
225     bool resolveAuthenticated() {
226         Boolean authc = getTypedValue!Boolean(AUTHENTICATED);
227         if (authc is null) {
228             //see if there is an AuthenticationInfo object.  If so, the very presence of one indicates a successful
229             //authentication attempt:
230             AuthenticationInfo info = getAuthenticationInfo();
231             authc = new Boolean(info !is null);
232         }
233 
234         if (!authc.value) {
235             //fall back to a session check:
236             Session session = resolveSession();
237             if (session !is null) {
238                 Boolean sessionAuthc = cast(Boolean) session.getAttribute(new String(AUTHENTICATED_SESSION_KEY));
239                 return sessionAuthc !is null && sessionAuthc.value;
240             }
241         }
242 
243         return authc.value;
244     }
245 
246     AuthenticationInfo getAuthenticationInfo() {
247         return getTypedValue!AuthenticationInfo(AUTHENTICATION_INFO);
248     }
249 
250     void setAuthenticationInfo(AuthenticationInfo info) {
251         nullSafePut(AUTHENTICATION_INFO, cast(Object)info);
252     }
253 
254     AuthenticationToken getAuthenticationToken() {
255         return getTypedValue!AuthenticationToken(AUTHENTICATION_TOKEN);
256     }
257 
258     void setAuthenticationToken(AuthenticationToken token) {
259         nullSafePut(AUTHENTICATION_TOKEN, cast(Object)token);
260     }
261 
262     string getHost() {
263         String s = getTypedValue!String(HOST);
264         if(s is null)
265             return null;
266         else
267             return s.value;
268     }
269 
270     void setHost(string host) {
271         if (!host.empty()) {
272             put(HOST, new String(host));
273         }
274     }
275 
276     string resolveHost() {
277         string host = getHost();
278 
279         if (host  is null) {
280             //check to see if there is an AuthenticationToken from which to retrieve it:
281             AuthenticationToken token = getAuthenticationToken();
282             HostAuthenticationToken hat = cast(HostAuthenticationToken) token;
283             if (hat !is null) {
284                 host = hat.getHost();
285             }
286         }
287 
288         if (host is null) {
289             Session session = resolveSession();
290             if (session !is null) {
291                 host = session.getHost();
292             }
293         }
294 
295         return host;
296     }
297 
298 }