1616// under the License.
1717package com .cloud .user ;
1818
19- import javax .inject .Inject ;
19+ import java .util .HashMap ;
20+ import java .util .Map ;
2021
21- import com .cloud .utils .component .ComponentContext ;
22+ import org .apache .log4j .Logger ;
23+ import org .apache .log4j .NDC ;
2224
25+ import com .cloud .dao .EntityManager ;
26+ import com .cloud .exception .CloudAuthenticationException ;
27+ import com .cloud .utils .exception .CloudRuntimeException ;
28+
29+ /**
30+ * Calling Context records information about who is making this call. This
31+ * class must be always be available in all CloudStack code. Every thread
32+ * entry point must set the context and remove it when the thread finishes.
33+ */
2334public class UserContext {
35+ private static final Logger s_logger = Logger .getLogger (UserContext .class );
2436 private static ThreadLocal <UserContext > s_currentContext = new ThreadLocal <UserContext >();
2537
26- private long userId ;
2738 private String sessionId ;
2839 private Account account ;
2940 private long startEventId = 0 ;
30- private long accountId ;
3141 private String eventDetails ;
32- private boolean apiServer ;
42+ private User user ;
43+ private final Map <String , Object > context = new HashMap <String , Object >();
44+
45+ private static EntityManager s_entityMgr ;
3346
34- @ Inject private AccountService _accountMgr = null ;
47+ public static void init (EntityManager entityMgr ) {
48+ s_entityMgr = entityMgr ;
49+ }
3550
3651 public UserContext () {
3752 }
3853
39- public UserContext (long userId , Account accountObject , String sessionId , boolean apiServer ) {
40- this .userId = userId ;
41- this .account = accountObject ;
54+ protected UserContext (User user , Account account , String sessionId ) {
55+ this .user = user ;
56+ this .account = account ;
4257 this .sessionId = sessionId ;
43- this .apiServer = apiServer ;
58+ }
59+
60+ public void putContextParameter (String key , Object value ) {
61+ context .put (key , value );
4462 }
4563
46- public long getCallerUserId ( ) {
47- return userId ;
64+ public Object getContextParameter ( String key ) {
65+ return context . get ( key ) ;
4866 }
4967
50- public User getCallerUser () {
51- if (_accountMgr == null ) {
52- _accountMgr = ComponentContext .getComponent (AccountService .class );
53- }
54- return _accountMgr .getActiveUser (userId );
68+ public long getCallingUserId () {
69+ return user .getId ();
5570 }
5671
57- public void setCallerUserId ( long userId ) {
58- this . userId = userId ;
72+ public User getCallingUser ( ) {
73+ return user ;
5974 }
6075
6176 public String getSessionId () {
6277 return sessionId ;
6378 }
6479
65- public Account getCaller () {
80+ public Account getCallingAccount () {
6681 return account ;
6782 }
6883
69- public void setCaller (Account accountObject ) {
70- this .account = accountObject ;
71- }
72-
73- public void setSessionKey (String sessionId ) {
74- this .sessionId = sessionId ;
75- }
76-
77- public boolean isApiServer () {
78- return apiServer ;
84+ public static UserContext current () {
85+ return s_currentContext .get ();
7986 }
8087
81- public void setApiServer (boolean apiServer ) {
82- this .apiServer = apiServer ;
88+ public static UserContext register (User callingUser , Account callingAccount , String sessionId ) {
89+ assert s_currentContext .get () == null : "There's a context already so what does this new register context mean? " + s_currentContext .get ().toString ();
90+ if (s_currentContext .get () != null ) { // FIXME: This should be removed soon. I added this check only to surface all the places that have this problem.
91+ throw new CloudRuntimeException ("There's a context already so what does this new register context mean? " + s_currentContext .get ().toString ());
92+ }
93+ UserContext callingContext = new UserContext (callingUser , callingAccount , sessionId );
94+ s_currentContext .set (callingContext );
95+ if (sessionId != null ) {
96+ NDC .push (sessionId );
97+ }
98+ s_logger .debug ("Setting calling context: " + s_currentContext .get ());
99+ return callingContext ;
83100 }
84101
85- public static UserContext current () {
102+ public static UserContext registerOnceOnly () {
86103 UserContext context = s_currentContext .get ();
87104 if (context == null ) {
88- //
89- // TODO: we should enforce explicit UserContext setup at major entry-points for security concerns,
90- // however, there are many places that run background jobs assume the system context.
91- //
92- // If there is a security concern, all entry points from user (including the front end that takes HTTP
93- // request in and
94- // the core async-job manager that runs commands from user) have explicitly setup the UserContext.
95- //
96- return UserContextInitializer .getInstance ().getAdminContext ();
105+ return register (User .UID_SYSTEM , Account .ACCOUNT_ID_SYSTEM , null );
97106 }
107+
108+ assert context .getCallingUserId () == User .UID_SYSTEM : "You are calling a very specific method that registers a one time system context. This method is meant for background threads that does processing." ;
98109 return context ;
99110 }
100111
101- public static void updateContext (long userId , Account accountObject , String sessionId ) {
102- UserContext context = current ();
103- assert (context != null ) : "Context should be already setup before you can call this one" ;
112+ public static UserContext register (String callingUserUuid , String callingAccountUuid , String sessionId ) {
113+ Account account = s_entityMgr .findByUuid (Account .class , callingAccountUuid );
114+ if (account == null ) {
115+ throw new CloudAuthenticationException ("The account is no longer current." ).add (Account .class , callingAccountUuid );
116+ }
117+
118+ User user = s_entityMgr .findByUuid (User .class , callingUserUuid );
119+ if (user == null ) {
120+ throw new CloudAuthenticationException ("The user is no longer current." ).add (User .class , callingUserUuid );
121+ }
122+ return register (user , account , sessionId );
123+ }
104124
105- context .setCallerUserId (userId );
106- context .setCaller (accountObject );
107- context .setSessionKey (sessionId );
125+ public static UserContext register (long callingUserId , long callingAccountId , String sessionId ) throws CloudAuthenticationException {
126+ Account account = s_entityMgr .findById (Account .class , callingAccountId );
127+ if (account == null ) {
128+ throw new CloudAuthenticationException ("The account is no longer current." ).add (Account .class , Long .toString (callingAccountId ));
129+ }
130+ User user = s_entityMgr .findById (User .class , callingUserId );
131+ if (user == null ) {
132+ throw new CloudAuthenticationException ("The user is no longer current." ).add (User .class , Long .toString (callingUserId ));
133+ }
134+ return register (user , account , sessionId );
108135 }
109136
110- public static void registerContext (long userId , Account accountObject , String sessionId , boolean apiServer ) {
111- s_currentContext .set (new UserContext (userId , accountObject , sessionId , apiServer ));
137+ public static UserContext register (long callingUserId , Account callingAccount , String sessionId , boolean apiServer ) {
138+ User user = s_entityMgr .findById (User .class , callingUserId );
139+ if (user == null ) {
140+ throw new CloudAuthenticationException ("The user is no longer current." ).add (User .class , Long .toString (callingUserId ));
141+ }
142+ return register (user , callingAccount , sessionId );
112143 }
113144
114- public static void unregisterContext () {
115- s_currentContext .set (null );
145+ public static UserContext unregister () {
146+ assert s_currentContext .get () != null : "Removing the context when we don't need to " + s_currentContext .get ().toString ();
147+ UserContext context = s_currentContext .get ();
148+ if (context == null ) {
149+ s_logger .trace ("No context to remove" );
150+ return null ;
151+ }
152+ s_currentContext .remove ();
153+ s_logger .debug ("Context removed " + context );
154+ String sessionId = context .getSessionId ();
155+ if (sessionId != null ) {
156+ while ((sessionId = NDC .pop ()) != null ) {
157+ if (context .getSessionId ().equals (sessionId )) {
158+ break ;
159+ }
160+ }
161+ }
162+ return context ;
116163 }
117164
118165 public void setStartEventId (long startEventId ) {
@@ -123,12 +170,16 @@ public long getStartEventId() {
123170 return startEventId ;
124171 }
125172
126- public long getAccountId () {
127- return accountId ;
173+ public long getCallingAccountId () {
174+ return account . getId () ;
128175 }
129176
130- public void setAccountId (long accountId ) {
131- this .accountId = accountId ;
177+ public String getCallingAccountUuid () {
178+ return account .getUuid ();
179+ }
180+
181+ public String getCallingUserUuid () {
182+ return user .getUuid ();
132183 }
133184
134185 public void setEventDetails (String eventDetails ) {
@@ -138,4 +189,12 @@ public void setEventDetails(String eventDetails) {
138189 public String getEventDetails () {
139190 return eventDetails ;
140191 }
192+
193+ @ Override
194+ public String toString () {
195+ return new StringBuffer ("CallContext[acct=" ).append (account .getId ())
196+ .append ("; user=" ).append (user .getId ())
197+ .append ("; session=" ).append (sessionId )
198+ .append ("]" ).toString ();
199+ }
141200}
0 commit comments