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.subject.support; 020 021import org.apache.shiro.mgt.SecurityManager; 022import org.apache.shiro.subject.Subject; 023import org.apache.shiro.util.CollectionUtils; 024import org.apache.shiro.util.ThreadContext; 025import org.apache.shiro.util.ThreadState; 026 027import java.util.Map; 028 029/** 030 * Manages thread-state for {@link Subject Subject} access (supporting 031 * {@code SecurityUtils.}{@link org.apache.shiro.SecurityUtils#getSubject() getSubject()} calls) 032 * during a thread's execution. 033 * <p/> 034 * The {@link #bind bind} method will bind a {@link Subject} and a 035 * {@link org.apache.shiro.mgt.SecurityManager SecurityManager} to the {@link ThreadContext} so they can be retrieved 036 * from the {@code ThreadContext} later by any 037 * {@code SecurityUtils.}{@link org.apache.shiro.SecurityUtils#getSubject() getSubject()} calls that might occur during 038 * the thread's execution. 039 * 040 * @since 1.0 041 */ 042public class SubjectThreadState implements ThreadState { 043 044 private Map<Object, Object> originalResources; 045 046 private final Subject subject; 047 private transient SecurityManager securityManager; 048 049 /** 050 * Creates a new {@code SubjectThreadState} that will bind and unbind the specified {@code Subject} to the 051 * thread 052 * 053 * @param subject the {@code Subject} instance to bind and unbind from the {@link ThreadContext}. 054 */ 055 public SubjectThreadState(Subject subject) { 056 if (subject == null) { 057 throw new IllegalArgumentException("Subject argument cannot be null."); 058 } 059 this.subject = subject; 060 061 SecurityManager securityManager = null; 062 if (subject instanceof DelegatingSubject) { 063 securityManager = ((DelegatingSubject) subject).getSecurityManager(); 064 } 065 if (securityManager == null) { 066 securityManager = ThreadContext.getSecurityManager(); 067 } 068 this.securityManager = securityManager; 069 } 070 071 /** 072 * Returns the {@code Subject} instance managed by this {@code ThreadState} implementation. 073 * 074 * @return the {@code Subject} instance managed by this {@code ThreadState} implementation. 075 */ 076 protected Subject getSubject() { 077 return this.subject; 078 } 079 080 /** 081 * Binds a {@link Subject} and {@link org.apache.shiro.mgt.SecurityManager SecurityManager} to the 082 * {@link ThreadContext} so they can be retrieved later by any 083 * {@code SecurityUtils.}{@link org.apache.shiro.SecurityUtils#getSubject() getSubject()} calls that might occur 084 * during the thread's execution. 085 * <p/> 086 * Prior to binding, the {@code ThreadContext}'s existing {@link ThreadContext#getResources() resources} are 087 * retained so they can be restored later via the {@link #restore restore} call. 088 */ 089 public void bind() { 090 SecurityManager securityManager = this.securityManager; 091 if (securityManager == null) { 092 //try just in case the constructor didn't find one at the time: 093 securityManager = ThreadContext.getSecurityManager(); 094 } 095 this.originalResources = ThreadContext.getResources(); 096 ThreadContext.remove(); 097 098 ThreadContext.bind(this.subject); 099 if (securityManager != null) { 100 ThreadContext.bind(securityManager); 101 } 102 } 103 104 /** 105 * {@link ThreadContext#remove Remove}s all thread-state that was bound by this instance. If any previous 106 * thread-bound resources existed prior to the {@link #bind bind} call, they are restored back to the 107 * {@code ThreadContext} to ensure the thread state is exactly as it was before binding. 108 */ 109 public void restore() { 110 ThreadContext.remove(); 111 if (!CollectionUtils.isEmpty(this.originalResources)) { 112 ThreadContext.setResources(this.originalResources); 113 } 114 } 115 116 /** 117 * Completely {@link ThreadContext#remove removes} the {@code ThreadContext} state. Typically this method should 118 * only be called in special cases - it is more 'correct' to {@link #restore restore} a thread to its previous 119 * state than to clear it entirely. 120 */ 121 public void clear() { 122 ThreadContext.remove(); 123 } 124}