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.mgt.RealmSecurityManager;
20 
21 import hunt.shiro.mgt.CachingSecurityManager;
22 
23 import hunt.shiro.cache.CacheManager;
24 import hunt.shiro.cache.CacheManagerAware;
25 import hunt.shiro.event.EventBus;
26 import hunt.shiro.event.EventBusAware;
27 import hunt.shiro.realm.Realm;
28 import hunt.shiro.util.LifecycleUtils;
29 
30 import hunt.collection;
31 import hunt.Exceptions;
32 import std.range;
33 
34 import hunt.logging.Logger;
35 
36 
37 /**
38  * Shiro support of a {@link SecurityManager} class hierarchy based around a collection of
39  * {@link hunt.shiro.realm.Realm}s.  All actual {@code SecurityManager} method implementations are left to
40  * subclasses.
41  *
42  */
43 abstract class RealmSecurityManager : CachingSecurityManager {
44 
45     /**
46      * Internal collection of <code>Realm</code>s used for all authentication and authorization operations.
47      */
48     // private Realm[] realms;
49     private Realm[] realms;
50 
51     /**
52      * Default no-arg constructor.
53      */
54     this() {
55         super();
56     }
57 
58     /**
59      * Convenience method for applications using a single realm that merely wraps the realm in a list and then invokes
60      * the {@link #setRealms} method.
61      *
62      * @param realm the realm to set for a single-realm application.
63      */
64      void setRealm(Realm realm) {
65         if (realm  is null) {
66             throw new IllegalArgumentException("Realm argument cannot be null");
67         }
68         // Realm[] realms = new ArrayList!(Realm)(1);
69         // realms.add(realm);
70         setRealms([realm]);
71     }
72 
73     /**
74      * Sets the realms managed by this <tt>SecurityManager</tt> instance.
75      *
76      * @param realms the realms managed by this <tt>SecurityManager</tt> instance.
77      * @throws IllegalArgumentException if the realms collection is null or empty.
78      */
79     //  void setRealms(Realm[] realms) {
80     //     if (realms  is null) {
81     //         throw new IllegalArgumentException("Realms collection argument cannot be null.");
82     //     }
83     //     if (realms.isEmpty()) {
84     //         throw new IllegalArgumentException("Realms collection argument cannot be empty.");
85     //     }
86     //     this.realms = realms;
87     //     afterRealmsSet();
88     // }
89 
90     void setRealms(Realm[] realms) {
91         if (realms.empty) {
92             throw new IllegalArgumentException("Realms collection argument cannot be empty.");
93         }
94         
95         // Realm[] r = new ArrayList!(Realm)(realms);
96         this.realms = realms;
97         afterRealmsSet();
98     }
99 
100     protected void afterRealmsSet() {
101         applyCacheManagerToRealms();
102         applyEventBusToRealms();
103     }
104 
105     /**
106      * Returns the {@link Realm Realm}s managed by this SecurityManager instance.
107      *
108      * @return the {@link Realm Realm}s managed by this SecurityManager instance.
109      */
110     Realm[] getRealms() {
111         return realms;
112     }
113 
114     /**
115      * Sets the internal {@link #getCacheManager CacheManager} on any internal configured
116      * {@link #getRealms Realms} that implement the {@link hunt.shiro.cache.CacheManagerAware CacheManagerAware} interface.
117      * <p/>
118      * This method is called after setting a cacheManager on this securityManager via the
119      * {@link #setCacheManager(hunt.shiro.cache.CacheManager) setCacheManager} method to allow it to be propagated
120      * down to all the internal Realms that would need to use it.
121      * <p/>
122      * It is also called after setting one or more realms via the {@link #setRealm setRealm} or
123      * {@link #setRealms setRealms} methods to allow these newly available realms to be given the cache manager
124      * already in use.
125      */
126     protected void applyCacheManagerToRealms() {
127         CacheManager cacheManager = getCacheManager();
128         Realm[] realms = getRealms();
129         if (cacheManager !is null && !realms.empty()) {
130             foreach(Realm realm ; realms) {
131                 CacheManagerAware ca = cast(CacheManagerAware) realm;
132                 if (ca !is null) {
133                     ca.setCacheManager(cacheManager);
134                 }
135             }
136         }
137     }
138 
139     /**
140      * Sets the internal {@link #getEventBus  EventBus} on any internal configured
141      * {@link #getRealms Realms} that implement the {@link EventBusAware} interface.
142      * <p/>
143      * This method is called after setting an eventBus on this securityManager via the
144      * {@link #setEventBus(hunt.shiro.event.EventBus) setEventBus} method to allow it to be propagated
145      * down to all the internal Realms that would need to use it.
146      * <p/>
147      * It is also called after setting one or more realms via the {@link #setRealm setRealm} or
148      * {@link #setRealms setRealms} methods to allow these newly available realms to be given the EventBus
149      * already in use.
150      *
151      */
152     protected void applyEventBusToRealms() {
153         EventBus eventBus = getEventBus();
154         Realm[] realms = getRealms();
155         if (eventBus !is null && !realms.empty()) {
156             foreach(Realm realm ; realms) {
157                 EventBusAware eba = cast(EventBusAware)realm;
158                 if (eba !is null) {
159                     eba.setEventBus(eventBus);
160                 }
161             }
162         }
163     }
164 
165     /**
166      * Simply calls {@link #applyCacheManagerToRealms() applyCacheManagerToRealms()} to allow the
167      * newly set {@link hunt.shiro.cache.CacheManager CacheManager} to be propagated to the internal collection of <code>Realm</code>
168      * that would need to use it.
169      */
170     override protected void afterCacheManagerSet() {
171         super.afterCacheManagerSet();
172         applyCacheManagerToRealms();
173     }
174 
175     override
176     protected void afterEventBusSet() {
177         super.afterEventBusSet();
178         applyEventBusToRealms();
179     }
180 
181     override void destroy() {
182         // LifecycleUtils.destroy(getRealms());
183         
184         Realm[] realms = getRealms();
185         
186         if(realms !is null) {
187             foreach(Realm r; realms) {
188                 LifecycleUtils.destroy(cast(Object)r);
189             }
190         }
191         this.realms = null;
192         super.destroy();
193     }
194 
195 }