1 /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package org.springframework.security.context; 17 18 import org.springframework.util.ReflectionUtils; 19 20 import java.lang.reflect.Constructor; 21 22 23 /** 24 * Associates a given {@link SecurityContext} with the current execution thread.<p>This class provides a series of 25 * static methods that delegate to an instance of {@link org.springframework.security.context.SecurityContextHolderStrategy}. The 26 * purpose of the class is to provide a convenient way to specify the strategy that should be used for a given JVM. 27 * This is a JVM-wide setting, since everything in this class is <code>static</code> to facilitate ease of use in 28 * calling code.</p> 29 * <p>To specify which strategy should be used, you must provide a mode setting. A mode setting is one of the 30 * three valid <code>MODE_</code> settings defined as <code>static final</code> fields, or a fully qualified classname 31 * to a concrete implementation of {@link org.springframework.security.context.SecurityContextHolderStrategy} that provides a 32 * public no-argument constructor.</p> 33 * <p>There are two ways to specify the desired strategy mode <code>String</code>. The first is to specify it via 34 * the system property keyed on {@link #SYSTEM_PROPERTY}. The second is to call {@link #setStrategyName(String)} 35 * before using the class. If neither approach is used, the class will default to using {@link #MODE_THREADLOCAL}, 36 * which is backwards compatible, has fewer JVM incompatibilities and is appropriate on servers (whereas {@link 37 * #MODE_GLOBAL} is definitely inappropriate for server use).</p> 38 * 39 * @author Ben Alex 40 * @version $Id: SecurityContextHolder.java 2217 2007-10-27 00:45:30Z luke_t $ 41 * 42 * @see org.springframework.security.context.HttpSessionContextIntegrationFilter 43 */ 44 public class SecurityContextHolder { 45 //~ Static fields/initializers ===================================================================================== 46 47 public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL"; 48 public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL"; 49 public static final String MODE_GLOBAL = "MODE_GLOBAL"; 50 public static final String SYSTEM_PROPERTY = "spring.security.strategy"; 51 private static String strategyName = System.getProperty(SYSTEM_PROPERTY); 52 private static SecurityContextHolderStrategy strategy; 53 private static int initializeCount = 0; 54 55 static { 56 initialize(); 57 } 58 59 //~ Methods ======================================================================================================== 60 61 /** 62 * Explicitly clears the context value from the current thread. 63 */ 64 public static void clearContext() { 65 strategy.clearContext(); 66 } 67 68 /** 69 * Obtain the current <code>SecurityContext</code>. 70 * 71 * @return the security context (never <code>null</code>) 72 */ 73 public static SecurityContext getContext() { 74 return strategy.getContext(); 75 } 76 77 /** 78 * Primarily for troubleshooting purposes, this method shows how many times the class has reinitialized its 79 * <code>SecurityContextHolderStrategy</code>. 80 * 81 * @return the count (should be one unless you've called {@link #setStrategyName(String)} to switch to an alternate 82 * strategy. 83 */ 84 public static int getInitializeCount() { 85 return initializeCount; 86 } 87 88 private static void initialize() { 89 if ((strategyName == null) || "".equals(strategyName)) { 90 // Set default 91 strategyName = MODE_THREADLOCAL; 92 } 93 94 if (strategyName.equals(MODE_THREADLOCAL)) { 95 strategy = new ThreadLocalSecurityContextHolderStrategy(); 96 } else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) { 97 strategy = new InheritableThreadLocalSecurityContextHolderStrategy(); 98 } else if (strategyName.equals(MODE_GLOBAL)) { 99 strategy = new GlobalSecurityContextHolderStrategy(); 100 } else { 101 // Try to load a custom strategy 102 try { 103 Class clazz = Class.forName(strategyName); 104 Constructor customStrategy = clazz.getConstructor(new Class[] {}); 105 strategy = (SecurityContextHolderStrategy) customStrategy.newInstance(new Object[] {}); 106 } catch (Exception ex) { 107 ReflectionUtils.handleReflectionException(ex); 108 } 109 } 110 111 initializeCount++; 112 } 113 114 /** 115 * Associates a new <code>SecurityContext</code> with the current thread of execution. 116 * 117 * @param context the new <code>SecurityContext</code> (may not be <code>null</code>) 118 */ 119 public static void setContext(SecurityContext context) { 120 strategy.setContext(context); 121 } 122 123 /** 124 * Changes the preferred strategy. Do <em>NOT</em> call this method more than once for a given JVM, as it 125 * will reinitialize the strategy and adversely affect any existing threads using the old strategy. 126 * 127 * @param strategyName the fully qualified classname of the strategy that should be used. 128 */ 129 public static void setStrategyName(String strategyName) { 130 SecurityContextHolder.strategyName = strategyName; 131 initialize(); 132 } 133 134 public String toString() { 135 return "SecurityContextHolder[strategy='" + strategyName + "'; initializeCount=" + initializeCount + "]"; 136 } 137 }