jchen21 commented on a change in pull request #7063:
URL: https://github.com/apache/geode/pull/7063#discussion_r740557034



##########
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:
       The null check for `clientUserAuths` is still needed.

##########
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:
       The synchronization here is not necessary, since you are using 
`ConcurrentMap` and  `CopyOnWriteArrayList`. You can use `putIfAbsent` instead 
of `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) {
+      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:
       This will shift every element in the list, which could be costly. When 
adding a new subject, it makes a copy of the array. At the same time, the other 
thread could call `subjects.get(0)` and get the old subject before the new one 
is added.

##########
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:
       Need a null check before calling `get(0)`. Otherwise it could throw 
`NullPointerException`.

##########
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:
       The extra synchronization is not necessary on `ConcurrentMap` and 
`CopyOnWriteArrayList`.

##########
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:
       `userId` here means `uniqueId` as in the previous line?

##########
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:
       `CopyOnWriteArrayList` offers built-in synchronization for all write 
access and it makes a copy of the underlying array for all write access. If you 
are trying to synchronize read and write access of the list with your own 
synchronization, it is not necessary to use `CopyOnWriteArrayList`. Because 
this introduces extra overhead of synchronization and copying the array.

##########
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:
       `CopyOnWriteArrayList` offers built-in synchronization for all write 
access and it makes a copy of the underlying array for all write access. If you 
are trying to synchronize read and write access of the list with your own 
synchronization, it is not necessary to use `CopyOnWriteArrayList`. Because 
this introduces extra overhead of synchronization and copying the array on 
write.

##########
File path: 
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuths.java
##########
@@ -90,28 +120,29 @@ public UserAuthAttributes getUserAuthAttributes(final Long 
userId) {
   }
 
   @VisibleForTesting
+  @TestOnly
   protected Collection<Subject> getSubjects() {

Review comment:
       It is better to make `getSubjects()` `synchronized` as well, even though 
it is for test only, in case something slips through the crack.




-- 
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]


Reply via email to