浏览代码

SEC-1763: Prevent nested switches in SwitchUserFilter by calling attemptExitUser() before doing the switch.

Luke Taylor 14 年之前
父节点
当前提交
de97bac85b

+ 14 - 3
web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java

@@ -75,11 +75,13 @@ import org.springframework.web.filter.GenericFilterBean;
  * <b>Note: This URL will be required to have appropriate security constraints configured so that only users of that
  * role can access it (e.g. ROLE_ADMIN).</b>
  * <p>
- * On a successful switch, the user's  <code>SecurityContextHolder</code> will be updated to reflect the
+ * On a successful switch, the user's  <code>SecurityContext</code> will be updated to reflect the
  * specified user and will also contain an additional
  * {@link org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority} which contains the original user.
+ * Before switching, a check will be made on whether the user is already currently switched, and any current switch will
+ * be exited to prevent "nested" switches.
  * <p>
- * To 'exit' from a user context, the user will then need to access a URL (see <code>exitUserUrl</code>)  that
+ * To 'exit' from a user context, the user needs to access a URL (see <code>exitUserUrl</code>)  that
  * will switch back to the original user as identified by the <code>ROLE_PREVIOUS_ADMINISTRATOR</code>.
  * <p>
  * To configure the Switch User Processing Filter, create a bean definition for the Switch User processing
@@ -288,7 +290,16 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
 
         // grant an additional authority that contains the original Authentication object
         // which will be used to 'exit' from the current switched user.
-        Authentication currentAuth = SecurityContextHolder.getContext().getAuthentication();
+
+        Authentication currentAuth;
+
+        try {
+            // SEC-1763. Check first if we are already switched.
+            currentAuth = attemptExitUser(request);
+        } catch (AuthenticationCredentialsNotFoundException e) {
+            currentAuth = SecurityContextHolder.getContext().getAuthentication();
+        }
+
         GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR, currentAuth);
 
         // get the original authorities

+ 20 - 0
web/src/test/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilterTests.java

@@ -374,6 +374,26 @@ public class SwitchUserFilterTests {
         assertTrue(AuthorityUtils.authorityListToSet(result.getAuthorities()).contains("ROLE_NEW"));
     }
 
+    // SEC-1763
+    @Test
+    public void nestedSwitchesAreNotAllowed() throws Exception {
+        // original user
+        UsernamePasswordAuthenticationToken source = new UsernamePasswordAuthenticationToken("orig", "hawaii50", ROLES_12);
+        SecurityContextHolder.getContext().setAuthentication(source);
+        SecurityContextHolder.getContext().setAuthentication(switchToUser("jacklord"));
+        Authentication switched = switchToUser("dano");
+
+        SwitchUserGrantedAuthority switchedFrom = null;
+
+        for (GrantedAuthority ga: switched.getAuthorities()) {
+            if (ga instanceof SwitchUserGrantedAuthority) {
+                switchedFrom = (SwitchUserGrantedAuthority)ga;
+                break;
+            }
+        }
+
+        assertSame(source, switchedFrom.getSource());
+    }
 
     //~ Inner Classes ==================================================================================================