Skip to content

Commit 54de6b4

Browse files
committed
Revamped UserContext
1 parent cd6aea1 commit 54de6b4

170 files changed

Lines changed: 761 additions & 801 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/src/com/cloud/user/UserContext.java

Lines changed: 115 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,103 +16,150 @@
1616
// under the License.
1717
package 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+
*/
2334
public 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
}

api/src/com/cloud/user/UserContextInitializer.java

Lines changed: 0 additions & 40 deletions
This file was deleted.

api/src/org/apache/cloudstack/api/BaseAsyncCmd.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ protected long saveStartedEvent() {
9898

9999
protected long saveStartedEvent(String eventType, String description, Long startEventId) {
100100
UserContext ctx = UserContext.current();
101-
Long userId = ctx.getCallerUserId();
101+
Long userId = ctx.getCallingUserId();
102102
userId = (userId == null) ? User.UID_SYSTEM : userId;
103103
Long startEvent = startEventId;
104104
if (startEvent == null) {
@@ -113,7 +113,7 @@ protected long saveCompletedEvent(String level, String description) {
113113

114114
protected long saveCompletedEvent(String level, String eventType, String description, Long startEventId) {
115115
UserContext ctx = UserContext.current();
116-
Long userId = ctx.getCallerUserId();
116+
Long userId = ctx.getCallingUserId();
117117
userId = (userId == null) ? User.UID_SYSTEM : userId;
118118
Long startEvent = startEventId;
119119
if (startEvent == null) {

api/src/org/apache/cloudstack/api/BaseListTemplateOrIsoPermissionsCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ protected Logger getLogger() {
8080
public void execute(){
8181
List<String> accountNames = _templateService.listTemplatePermissions(this);
8282

83-
Account account = UserContext.current().getCaller();
83+
Account account = UserContext.current().getCallingAccount();
8484
boolean isAdmin = (isAdmin(account.getType()));
8585

8686
TemplatePermissionsResponse response = _responseGenerator.createTemplatePermissionsResponse(accountNames, id, isAdmin);

api/src/org/apache/cloudstack/api/command/admin/account/DeleteAccountCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public String getCommandName() {
7575

7676
@Override
7777
public long getEntityOwnerId() {
78-
Account account = UserContext.current().getCaller();// Let's give the caller here for event logging.
78+
Account account = UserContext.current().getCallingAccount();// Let's give the caller here for event logging.
7979
if (account != null) {
8080
return account.getAccountId();
8181
}

api/src/org/apache/cloudstack/api/command/admin/host/CancelMaintenanceCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static String getResultObjectName() {
6969

7070
@Override
7171
public long getEntityOwnerId() {
72-
Account account = UserContext.current().getCaller();
72+
Account account = UserContext.current().getCallingAccount();
7373
if (account != null) {
7474
return account.getId();
7575
}

api/src/org/apache/cloudstack/api/command/admin/host/PrepareForMaintenanceCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static String getResultObjectName() {
6969

7070
@Override
7171
public long getEntityOwnerId() {
72-
Account account = UserContext.current().getCaller();
72+
Account account = UserContext.current().getCallingAccount();
7373
if (account != null) {
7474
return account.getId();
7575
}

api/src/org/apache/cloudstack/api/command/admin/host/ReconnectHostCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static String getResultObjectName() {
6969

7070
@Override
7171
public long getEntityOwnerId() {
72-
Account account = UserContext.current().getCaller();
72+
Account account = UserContext.current().getCallingAccount();
7373
if (account != null) {
7474
return account.getId();
7575
}

api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public String getCommandName() {
6565

6666
@Override
6767
public long getEntityOwnerId() {
68-
Account account = UserContext.current().getCaller();
68+
Account account = UserContext.current().getCallingAccount();
6969
if (account != null) {
7070
return account.getId();
7171
}

api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void execute() throws ConcurrentOperationException, ResourceUnavailableEx
109109
if (router == null || router.getRole() != Role.INTERNAL_LB_VM) {
110110
throw new InvalidParameterValueException("Can't find internal lb vm by id");
111111
} else {
112-
result = _internalLbSvc.startInternalLbVm(getId(), UserContext.current().getCaller(), UserContext.current().getCallerUserId());
112+
result = _internalLbSvc.startInternalLbVm(getId(), UserContext.current().getCallingAccount(), UserContext.current().getCallingUserId());
113113
}
114114

115115
if (result != null){

0 commit comments

Comments
 (0)