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