jinmeiliao commented on a change in pull request #7063:
URL: https://github.com/apache/geode/pull/7063#discussion_r741183948
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientProxy.java
##########
@@ -774,14 +770,22 @@ protected boolean close(boolean checkQueue, boolean
stoppedNormally) {
connected = false;
- // Close the Authorization callback (if any)
+ // Close the Authorization callback or subject if we are not keeping the
proxy
try {
if (!pauseDurable) {
- if (postAuthzCallback != null) {// for single user
+ // single user case -- old security
+ if (postAuthzCallback != null) {
postAuthzCallback.close();
postAuthzCallback = null;
}
- if (clientUserAuths != null) {// for multiple users
+ // single user case -- integrated security
+ // connection is closed, so we can log out this subject
+ else if (subject != null) {
+ logger.debug("CacheClientProxy.close, logging out: " +
subject.getPrincipal());
+ subject.logout();
+ }
+ // for multiUser case, in non-durable case, we are closing the
connection
+ else {
Review comment:
`clientUserAuths` is always initialized, could not be null.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientProxy.java
##########
@@ -774,14 +770,22 @@ protected boolean close(boolean checkQueue, boolean
stoppedNormally) {
connected = false;
- // Close the Authorization callback (if any)
+ // Close the Authorization callback or subject if we are not keeping the
proxy
try {
if (!pauseDurable) {
- if (postAuthzCallback != null) {// for single user
+ // single user case -- old security
+ if (postAuthzCallback != null) {
postAuthzCallback.close();
postAuthzCallback = null;
}
- if (clientUserAuths != null) {// for multiple users
+ // single user case -- integrated security
+ // connection is closed, so we can log out this subject
+ else if (subject != null) {
+ logger.debug("CacheClientProxy.close, logging out: " +
subject.getPrincipal());
+ subject.logout();
+ }
+ // for multiUser case, in non-durable case, we are closing the
connection
+ else {
Review comment:
`clientUserAuths` is always initialized, could not be null.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientProxy.java
##########
@@ -774,14 +770,22 @@ protected boolean close(boolean checkQueue, boolean
stoppedNormally) {
connected = false;
- // Close the Authorization callback (if any)
+ // Close the Authorization callback or subject if we are not keeping the
proxy
try {
if (!pauseDurable) {
- if (postAuthzCallback != null) {// for single user
+ // single user case -- old security
+ if (postAuthzCallback != null) {
postAuthzCallback.close();
postAuthzCallback = null;
}
- if (clientUserAuths != null) {// for multiple users
+ // single user case -- integrated security
+ // connection is closed, so we can log out this subject
+ else if (subject != null) {
+ logger.debug("CacheClientProxy.close, logging out: " +
subject.getPrincipal());
+ subject.logout();
+ }
+ // for multiUser case, in non-durable case, we are closing the
connection
+ else {
Review comment:
`clientUserAuths` is always initialized, should not be null, but we can
add the null check.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -52,17 +62,32 @@ public Long putUserAuth(UserAuthAttributes userAuthAttr) {
return newId;
}
- public Long putSubject(Subject subject, long existingUniqueId) {
- final Long newId;
+
+ public long putSubject(@NotNull Subject subject, long existingUniqueId) {
+ final long newId;
if (existingUniqueId == 0 || existingUniqueId == NOT_A_USER_ID) {
newId = getNextID();
} else {
newId = existingUniqueId;
}
- Subject oldSubject = uniqueIdVsSubject.put(newId, subject);
- removeSubject(oldSubject);
- logger.debug("Subject of {} added.", newId);
+ // we are saving all the subjects that's related to this uniqueId
+ // we cannot immediately log out the old subject of this userId because
Review comment:
yes.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -52,17 +62,32 @@ public Long putUserAuth(UserAuthAttributes userAuthAttr) {
return newId;
}
- public Long putSubject(Subject subject, long existingUniqueId) {
- final Long newId;
+
+ public long putSubject(@NotNull Subject subject, long existingUniqueId) {
+ final long newId;
if (existingUniqueId == 0 || existingUniqueId == NOT_A_USER_ID) {
newId = getNextID();
} else {
newId = existingUniqueId;
}
- Subject oldSubject = uniqueIdVsSubject.put(newId, subject);
- removeSubject(oldSubject);
- logger.debug("Subject of {} added.", newId);
+ // we are saving all the subjects that's related to this uniqueId
+ // we cannot immediately log out the old subject of this userId because
+ // it might already be bound to another thread and doing operations. If
+ // we log out that subject immediately, that thread "authorize" would get
null principal.
+ synchronized (this) {
+ CopyOnWriteArrayList<Subject> subjects;
+ if (!uniqueIdVsSubject.containsKey(newId)) {
+ logger.debug("Subject of {} added.", newId);
+ subjects = new CopyOnWriteArrayList<>();
+ uniqueIdVsSubject.put(newId, subjects);
+ } else {
+ logger.debug("Subject of {} replaced.", newId);
+ subjects = uniqueIdVsSubject.get(newId);
+ }
+ // always add the latest subject to the top of the list;
+ subjects.add(0, subject);
Review comment:
for performance concerns, after we fix multiple threads in the client
could send in authentication requests, `putSubject` should only be called
multiple times with the same uniqueId when credentials expires, which is not
that frequent. I think we ignore the cost issue.
put/get are synchronized on the object itself, so there should not be
`get(0)` happening while other thread is doing the put.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -90,28 +115,29 @@ public UserAuthAttributes getUserAuthAttributes(final Long
userId) {
}
@VisibleForTesting
+ @TestOnly
protected Collection<Subject> getSubjects() {
- return Collections.unmodifiableCollection(uniqueIdVsSubject.values());
+ List<Subject> all = uniqueIdVsSubject.values().stream()
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
+ return Collections.unmodifiableCollection(all);
}
- public Subject getSubject(final Long userId) {
- return uniqueIdVsSubject.get(userId);
+ public synchronized Subject getSubject(final Long userId) {
+ CopyOnWriteArrayList<Subject> subjects = uniqueIdVsSubject.get(userId);
+ if (subjects == null || subjects.isEmpty()) {
+ return null;
+ }
+ return subjects.get(0);
}
- public void removeSubject(final Long userId) {
+ public synchronized void removeSubject(final Long userId) {
Review comment:
this prevents other thread doing `put/get` at the same time.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -121,7 +147,7 @@ public UserAuthAttributes getUserAuthAttributes(final
String cqName) {
public Subject getSubject(final String cqName) {
Long uniqueId = cqNameVsUniqueId.get(cqName);
if (uniqueId != null) {
- return uniqueIdVsSubject.get(uniqueId);
+ return uniqueIdVsSubject.get(uniqueId).get(0);
Review comment:
good catch!
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -52,17 +62,32 @@ public Long putUserAuth(UserAuthAttributes userAuthAttr) {
return newId;
}
- public Long putSubject(Subject subject, long existingUniqueId) {
- final Long newId;
+
+ public long putSubject(@NotNull Subject subject, long existingUniqueId) {
+ final long newId;
if (existingUniqueId == 0 || existingUniqueId == NOT_A_USER_ID) {
newId = getNextID();
} else {
newId = existingUniqueId;
}
- Subject oldSubject = uniqueIdVsSubject.put(newId, subject);
- removeSubject(oldSubject);
- logger.debug("Subject of {} added.", newId);
+ // we are saving all the subjects that's related to this uniqueId
+ // we cannot immediately log out the old subject of this userId because
+ // it might already be bound to another thread and doing operations. If
+ // we log out that subject immediately, that thread "authorize" would get
null principal.
+ synchronized (this) {
Review comment:
we are preventing user doing `putSubject` `getSubject`, `removeSubject`
at the same time. this `synchronize` block is necessary.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -52,17 +62,32 @@ public Long putUserAuth(UserAuthAttributes userAuthAttr) {
return newId;
}
- public Long putSubject(Subject subject, long existingUniqueId) {
- final Long newId;
+
+ public long putSubject(@NotNull Subject subject, long existingUniqueId) {
+ final long newId;
if (existingUniqueId == 0 || existingUniqueId == NOT_A_USER_ID) {
newId = getNextID();
} else {
newId = existingUniqueId;
}
- Subject oldSubject = uniqueIdVsSubject.put(newId, subject);
- removeSubject(oldSubject);
- logger.debug("Subject of {} added.", newId);
+ // we are saving all the subjects that's related to this uniqueId
+ // we cannot immediately log out the old subject of this userId because
+ // it might already be bound to another thread and doing operations. If
+ // we log out that subject immediately, that thread "authorize" would get
null principal.
+ synchronized (this) {
+ CopyOnWriteArrayList<Subject> subjects;
+ if (!uniqueIdVsSubject.containsKey(newId)) {
+ logger.debug("Subject of {} added.", newId);
+ subjects = new CopyOnWriteArrayList<>();
+ uniqueIdVsSubject.put(newId, subjects);
+ } else {
+ logger.debug("Subject of {} replaced.", newId);
+ subjects = uniqueIdVsSubject.get(newId);
+ }
+ // always add the latest subject to the top of the list;
+ subjects.add(0, subject);
Review comment:
for performance concerns, after we fix multiple threads in the client
could send in authentication requests, `putSubject` should only be called
multiple times with the same uniqueId when credentials expires, which is not
that frequent. I think we can ignore the cost issue.
put/get are synchronized on the object itself, so there should not be
`get(0)` happening while other thread is doing the put.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -52,17 +62,32 @@ public Long putUserAuth(UserAuthAttributes userAuthAttr) {
return newId;
}
- public Long putSubject(Subject subject, long existingUniqueId) {
- final Long newId;
+
+ public long putSubject(@NotNull Subject subject, long existingUniqueId) {
+ final long newId;
if (existingUniqueId == 0 || existingUniqueId == NOT_A_USER_ID) {
newId = getNextID();
} else {
newId = existingUniqueId;
}
- Subject oldSubject = uniqueIdVsSubject.put(newId, subject);
- removeSubject(oldSubject);
- logger.debug("Subject of {} added.", newId);
+ // we are saving all the subjects that's related to this uniqueId
+ // we cannot immediately log out the old subject of this userId because
+ // it might already be bound to another thread and doing operations. If
+ // we log out that subject immediately, that thread "authorize" would get
null principal.
+ synchronized (this) {
Review comment:
that's true, it might be redundant using that list. I can change it to
use regular list
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]