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.ini; 020 021import org.apache.shiro.config.ConfigurationException; 022import org.apache.shiro.config.Ini; 023import org.apache.shiro.config.ogdl.ReflectionBuilder; 024import org.apache.shiro.mgt.DefaultSecurityManager; 025import org.apache.shiro.mgt.RealmSecurityManager; 026import org.apache.shiro.mgt.SecurityManager; 027import org.apache.shiro.realm.Realm; 028import org.apache.shiro.realm.RealmFactory; 029import org.apache.shiro.realm.text.IniRealm; 030import org.apache.shiro.util.CollectionUtils; 031import org.apache.shiro.lang.util.Factory; 032import org.apache.shiro.lang.util.LifecycleUtils; 033import org.apache.shiro.lang.util.Nameable; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037import java.util.ArrayList; 038import java.util.Collection; 039import java.util.Collections; 040import java.util.LinkedHashMap; 041import java.util.List; 042import java.util.Map; 043 044/** 045 * A {@link Factory} that creates {@link SecurityManager} instances based on {@link Ini} configuration. 046 * 047 * @since 1.0 048 * @deprecated use Shiro's {@code Environment} mechanisms instead. 049 */ 050@Deprecated 051public class IniSecurityManagerFactory extends IniFactorySupport<SecurityManager> { 052 053 /** 054 * main section name. 055 */ 056 public static final String MAIN_SECTION_NAME = "main"; 057 058 /** 059 * security manager name. 060 */ 061 public static final String SECURITY_MANAGER_NAME = "securityManager"; 062 063 /** 064 * ini realm name. 065 */ 066 public static final String INI_REALM_NAME = "iniRealm"; 067 068 private static final Logger LOGGER = LoggerFactory.getLogger(IniSecurityManagerFactory.class); 069 070 private ReflectionBuilder builder; 071 072 /** 073 * Creates a new instance. See the {@link #getInstance()} JavaDoc for detailed explanation of how an INI 074 * source will be resolved to use to build the instance. 075 */ 076 public IniSecurityManagerFactory() { 077 this.builder = new ReflectionBuilder(); 078 } 079 080 public IniSecurityManagerFactory(Ini config) { 081 this(); 082 setIni(config); 083 } 084 085 public IniSecurityManagerFactory(String iniResourcePath) { 086 this(Ini.fromResourcePath(iniResourcePath)); 087 } 088 089 public Map<String, ?> getBeans() { 090 return this.builder != null ? Collections.unmodifiableMap(builder.getObjects()) : null; 091 } 092 093 public void destroy() { 094 if (getReflectionBuilder() != null) { 095 getReflectionBuilder().destroy(); 096 } 097 } 098 099 private SecurityManager getSecurityManagerBean() { 100 return getReflectionBuilder().getBean(SECURITY_MANAGER_NAME, SecurityManager.class); 101 } 102 103 protected SecurityManager createDefaultInstance() { 104 return new DefaultSecurityManager(); 105 } 106 107 protected SecurityManager createInstance(Ini ini) { 108 if (CollectionUtils.isEmpty(ini)) { 109 throw new NullPointerException("Ini argument cannot be null or empty."); 110 } 111 SecurityManager securityManager = createSecurityManager(ini); 112 if (securityManager == null) { 113 String msg = SecurityManager.class + " instance cannot be null."; 114 throw new ConfigurationException(msg); 115 } 116 return securityManager; 117 } 118 119 private SecurityManager createSecurityManager(Ini ini) { 120 return createSecurityManager(ini, getConfigSection(ini)); 121 } 122 123 private Ini.Section getConfigSection(Ini ini) { 124 125 Ini.Section mainSection = ini.getSection(MAIN_SECTION_NAME); 126 if (CollectionUtils.isEmpty(mainSection)) { 127 //try the default: 128 mainSection = ini.getSection(Ini.DEFAULT_SECTION_NAME); 129 } 130 return mainSection; 131 } 132 133 protected boolean isAutoApplyRealms(SecurityManager securityManager) { 134 boolean autoApply = true; 135 if (securityManager instanceof RealmSecurityManager) { 136 //only apply realms if they haven't been explicitly set by the user: 137 RealmSecurityManager realmSecurityManager = (RealmSecurityManager) securityManager; 138 Collection<Realm> realms = realmSecurityManager.getRealms(); 139 if (!CollectionUtils.isEmpty(realms)) { 140 LOGGER.info("Realms have been explicitly set on the SecurityManager instance - auto-setting of " 141 + "realms will not occur."); 142 autoApply = false; 143 } 144 } 145 return autoApply; 146 } 147 148 @SuppressWarnings({"unchecked"}) 149 private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) { 150 151 getReflectionBuilder().setObjects(createDefaults(ini, mainSection)); 152 Map<String, ?> objects = buildInstances(mainSection); 153 154 SecurityManager securityManager = getSecurityManagerBean(); 155 156 boolean autoApplyRealms = isAutoApplyRealms(securityManager); 157 158 if (autoApplyRealms) { 159 //realms and realm factory might have been created - pull them out first so we can 160 //initialize the securityManager: 161 Collection<Realm> realms = getRealms(objects); 162 //set them on the SecurityManager 163 if (!CollectionUtils.isEmpty(realms)) { 164 applyRealmsToSecurityManager(realms, securityManager); 165 } 166 } 167 168 return securityManager; 169 } 170 171 protected Map<String, ?> createDefaults(Ini ini, Ini.Section mainSection) { 172 Map<String, Object> defaults = new LinkedHashMap<String, Object>(); 173 174 SecurityManager securityManager = createDefaultInstance(); 175 defaults.put(SECURITY_MANAGER_NAME, securityManager); 176 177 if (shouldImplicitlyCreateRealm(ini)) { 178 Realm realm = createRealm(ini); 179 if (realm != null) { 180 defaults.put(INI_REALM_NAME, realm); 181 } 182 } 183 184 // The values from 'getDefaults()' will override the above. 185 Map<String, ?> defaultBeans = getDefaults(); 186 if (!CollectionUtils.isEmpty(defaultBeans)) { 187 defaults.putAll(defaultBeans); 188 } 189 190 return defaults; 191 } 192 193 private Map<String, ?> buildInstances(Ini.Section section) { 194 return getReflectionBuilder().buildObjects(section); 195 } 196 197 private void addToRealms(Collection<Realm> realms, RealmFactory factory) { 198 LifecycleUtils.init(factory); 199 Collection<Realm> factoryRealms = factory.getRealms(); 200 //SHIRO-238: check factoryRealms (was 'realms'): 201 if (!CollectionUtils.isEmpty(factoryRealms)) { 202 realms.addAll(factoryRealms); 203 } 204 } 205 206 private Collection<Realm> getRealms(Map<String, ?> instances) { 207 208 //realms and realm factory might have been created - pull them out first so we can 209 //initialize the securityManager: 210 List<Realm> realms = new ArrayList<Realm>(); 211 212 //iterate over the map entries to pull out the realm factory(s): 213 for (Map.Entry<String, ?> entry : instances.entrySet()) { 214 215 String name = entry.getKey(); 216 Object value = entry.getValue(); 217 218 if (value instanceof RealmFactory) { 219 addToRealms(realms, (RealmFactory) value); 220 } else if (value instanceof Realm) { 221 Realm realm = (Realm) value; 222 //set the name if null: 223 String existingName = realm.getName(); 224 if (existingName == null || existingName.startsWith(realm.getClass().getName())) { 225 if (realm instanceof Nameable) { 226 ((Nameable) realm).setName(name); 227 LOGGER.debug("Applied name '{}' to Nameable realm instance {}", name, realm); 228 } else { 229 LOGGER.info("Realm does not implement the {} interface. Configured name will not be applied.", 230 Nameable.class.getName()); 231 } 232 } 233 realms.add(realm); 234 } 235 } 236 237 return realms; 238 } 239 240 private void assertRealmSecurityManager(SecurityManager securityManager) { 241 if (securityManager == null) { 242 throw new NullPointerException("securityManager instance cannot be null"); 243 } 244 if (!(securityManager instanceof RealmSecurityManager)) { 245 String msg = "securityManager instance is not a " + RealmSecurityManager.class.getName() 246 + " instance. This is required to access or configure realms on the instance."; 247 throw new ConfigurationException(msg); 248 } 249 } 250 251 protected void applyRealmsToSecurityManager(Collection<Realm> realms, SecurityManager securityManager) { 252 assertRealmSecurityManager(securityManager); 253 ((RealmSecurityManager) securityManager).setRealms(realms); 254 } 255 256 /** 257 * Returns {@code true} if the Ini contains account data and a {@code Realm} should be implicitly 258 * {@link #createRealm(Ini) created} to reflect the account data, {@code false} if no realm should be implicitly 259 * created. 260 * 261 * @param ini the Ini instance to inspect for account data resulting in an implicitly created realm. 262 * @return {@code true} if the Ini contains account data and a {@code Realm} should be implicitly 263 * {@link #createRealm(Ini) created} to reflect the account data, {@code false} if no realm should be 264 * implicitly created. 265 */ 266 protected boolean shouldImplicitlyCreateRealm(Ini ini) { 267 return !CollectionUtils.isEmpty(ini) 268 && (!CollectionUtils.isEmpty(ini.getSection(IniRealm.ROLES_SECTION_NAME)) 269 || !CollectionUtils.isEmpty(ini.getSection(IniRealm.USERS_SECTION_NAME))); 270 } 271 272 /** 273 * Creates a {@code Realm} from the Ini instance containing account data. 274 * 275 * @param ini the Ini instance from which to acquire the account data. 276 * @return a new Realm instance reflecting the account data discovered in the {@code Ini}. 277 */ 278 protected Realm createRealm(Ini ini) { 279 //IniRealm realm = new IniRealm(ini); changed to support SHIRO-322 280 IniRealm realm = new IniRealm(); 281 realm.setName(INI_REALM_NAME); 282 //added for SHIRO-322 283 realm.setIni(ini); 284 return realm; 285 } 286 287 /** 288 * Returns the ReflectionBuilder instance used to create SecurityManagers object graph. 289 * 290 * @return ReflectionBuilder instance used to create SecurityManagers object graph. 291 * @since 1.4 292 */ 293 public ReflectionBuilder getReflectionBuilder() { 294 return builder; 295 } 296 297 /** 298 * Sets the ReflectionBuilder that will be used to create the SecurityManager based on the contents of 299 * the Ini configuration. 300 * 301 * @param builder The ReflectionBuilder used to parse the Ini configuration. 302 * @since 1.4 303 */ 304 @SuppressWarnings("unused") 305 public void setReflectionBuilder(ReflectionBuilder builder) { 306 this.builder = builder; 307 } 308}