CVE-2020-5206 (published 2020-01-30T22:15Z)

In Opencast before 7.6 and 8.1, using a remember-me cookie with an arbitrary username can cause Opencast to assume proper authentication for that user even if the remember-me cookie was incorrect given that the attacked endpoint also allows anonymous access. This way, an attacker can, for example, fake a remember-me token, assume the identity of the global system administrator and request non-public content from the search service without ever providing any proper authentication. This problem is fixed in Opencast 7.6 and Opencast 8.1

Severity: MEDIUM
CVSS v2 base score: 6.4 (AV:N/AC:L/Au:N/C:P/I:P/A:N)
CVSS v3 base score: 10.0, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)

Weakness information:
cwe_id: CWE-287
cwe_name: Improper Authentication
description: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
extended_description: 
            
			
         
         

Fix information:
repo_url: https://github.com/opencast/opencast
commit_details: repo_url: https://github.com/opencast/opencast
author: Lars Kiesow
author_date: 2020-01-13 23:55:50+01:00
msg: Authentication Bypass For Endpoints With Anonymous Access

Using a remember-me cookie with an arbitrary username can cause Opencast
to assume proper authentication for that user even if the remember-me
cookie was incorrect given that the attacked endpoint also allows
anonymous access.

This way, an attacker can, for example, fake a remember-me token, assume
the identity of the global system administrator and request non-public
content from the search service without ever providing any proper
authentication.

The reason for this problem is that using a remember-me cookie will
always cause the user in the request context to be populated, even if
the cookie is invalid by now. This is usually no problem, except in
combination with anonymous access where anonymous authentication is
granted and the request may continue.

In such a case, Opencast's security service would just check that a user
existed in the request context and assume proper authentication of this
user, never checking if it's actually anonymous authentication.

This patch adds this additional check, falling back to the anonymous
user in case of anonymous authentication.
repository: repo_url: https://github.com/opencast/opencast
repo_name: opencast/opencast
description: The free and open source solution for automated video capture and distribution at scale.
repo_language: Java
owner: opencast
file_changes: filename: SecurityServiceSpringImpl.java
change_type: ModificationType.MODIFY
diff: @@ -32,6 +32,7 @@ import org.opencastproject.security.util.SecurityUtil;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -94,15 +95,19 @@ public class SecurityServiceSpringImpl implements SecurityService {
 
     User delegatedUser = delegatedUserHolder.get();
 
+    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+    if (auth instanceof AnonymousAuthenticationToken) {
+      return SecurityUtil.createAnonymousUser(org);
+    }
+
     if (delegatedUser != null) {
       return delegatedUser;
     }
 
-    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
     JaxbOrganization jaxbOrganization = JaxbOrganization.fromOrganization(org);
     if (auth != null) {
       Object principal = auth.getPrincipal();
-      if ((principal != null) && (principal instanceof UserDetails)) {
+      if ((principal instanceof UserDetails)) {
         UserDetails userDetails = (UserDetails) principal;
 
         User user = null;
@@ -111,16 +116,15 @@ public class SecurityServiceSpringImpl implements SecurityService {
         if (userDirectory != null) {
           user = userDirectory.loadUser(userDetails.getUsername());
           if (user == null) {
-            logger.debug(
-                    "Authenticated user '{}' could not be found in any of the current UserProviders. Continuing anyway...",
-                    userDetails.getUsername());
+            logger.debug("Authenticated user '{}' could not be found in any of the current UserProviders. "
+                + "Continuing anyway...", userDetails.getUsername());
           }
         } else {
           logger.debug("No UserDirectory was found when trying to search for user '{}'", userDetails.getUsername());
         }
 
         // Add the roles (authorities) in the security context
-        Set<JaxbRole> roles = new HashSet<JaxbRole>();
+        Set<JaxbRole> roles = new HashSet<>();
         Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
         if (authorities != null) {
           for (GrantedAuthority ga : authorities) {

programming_language: Java