Moderate severityNVD Advisory· Published Jan 30, 2020· Updated Aug 4, 2024
Hard-Coded Key Used For Remember-me Token in OpenCast
CVE-2020-5222
Description
Opencast before 7.6 and 8.1 enables a remember-me cookie based on a hash created from the username, password, and an additional system key. This means that an attacker getting access to a remember-me token for one server can get access to all servers which allow log-in using the same credentials without ever needing the credentials. This problem is fixed in Opencast 7.6 and Opencast 8.1
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.opencastproject:opencast-kernelMaven | < 7.6 | 7.6 |
org.opencastproject:opencast-kernelMaven | >= 8.0, < 8.1 | 8.1 |
Affected products
1Patches
11a7172c95af8Fix Remember-Me Cookie
2 files changed · +146 −1
etc/security/mh_default_org.xml+10 −1 modified@@ -326,7 +326,7 @@ --> <!-- Enables "remember me" functionality --> - <sec:remember-me key="opencast" user-service-ref="userDetailsService" /> + <sec:remember-me services-ref="rememberMeServices" /> <!-- Set the request cache --> <sec:request-cache ref="requestCache" /> @@ -344,6 +344,15 @@ </sec:http> + <bean id="rememberMeServices" class="org.opencastproject.kernel.security.SystemTokenBasedRememberMeService"> + <property name="userDetailsService" ref="userDetailsService"/> + <!-- All following settings are optional --> + <property name="tokenValiditySeconds" value="1209600"/> + <property name="cookieName" value="oc-remember-me"/> + <!-- The following key will be augmented by system properties. Thus, leaving this untouched is okay --> + <property name="key" value="opencast"/> + </bean> + <!-- ############################# --> <!-- # Authentication Filters # --> <!-- ############################# -->
modules/kernel/src/main/java/org/opencastproject/kernel/security/SystemTokenBasedRememberMeService.java+136 −0 added@@ -0,0 +1,136 @@ +/** + * Licensed to The Apereo Foundation under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * + * The Apereo Foundation licenses this file to you under the Educational + * Community License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at: + * + * http://opensource.org/licenses/ecl2.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + */ + +package org.opencastproject.kernel.security; + +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.codec.Hex; +import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Objects; + +/** + * This implements a zero-configuration version Spring Security's token based remember-me service. While the key can + * still be augmented by configuration, it is generally generated based on seldom changing but unique system + * properties like hostname, IP address, file system information and Linux kernel. + */ +public class SystemTokenBasedRememberMeService extends TokenBasedRememberMeServices { + private Logger logger = LoggerFactory.getLogger(SystemTokenBasedRememberMeService.class); + private String key; + + @Deprecated + public SystemTokenBasedRememberMeService() { + super(); + setKey(null); + } + + public SystemTokenBasedRememberMeService(String key, UserDetailsService userDetailsService) { + super(key, userDetailsService); + setKey(key); + } + + /** + * Set a new key to be used when generating remember-me tokens. + * + * Note that the key passed to this method will be augmented by seldom changing but generally unique system + * properties like hostname, IP address, file system information and Linux kernel. Hence, even setting no custom + * key should be save. + */ + @Override + public void setKey(String key) { + // Start with a user key if provided + StringBuilder keyBuilder = new StringBuilder(Objects.toString(key, "")); + + // This will give us the hostname and IP address as something which should be unique per system. + // For example: lk.elan-ev.de/10.10.10.31 + try { + keyBuilder.append(InetAddress.getLocalHost()); + } catch (UnknownHostException e) { + // silently ignore this + } + + // Gather additional system properties as key + // This requires a proc-fs which should generally be available under Linux. + // But even without, we have fallbacks above and below. + for (String procFile: Arrays.asList("/proc/version", "/proc/partitions")) { + try (FileInputStream fileInputStream = new FileInputStream(new File(procFile))) { + keyBuilder.append(IOUtils.toString(fileInputStream, StandardCharsets.UTF_8)); + } catch (IOException e) { + // ignore this + } + } + + // If we still have no proper key, just generate a random one. + // This will work just fine with the single drawback that restarting Opencast invalidates all remember-me tokens. + // But it should be a sufficiently good fallback. + key = keyBuilder.toString(); + if (key.isEmpty()) { + logger.warn("Could not generate semi-persistent remember-me key. Will generate a non-persistent random one."); + key = Double.toString(Math.random()); + } + logger.debug("Remember me key before hashing: {}", key); + + // Use a SHA-512 hash as key to have a more sane key. + try { + MessageDigest digest = MessageDigest.getInstance("SHA-512"); + key = new String(Hex.encode(digest.digest(key.getBytes()))); + } catch (NoSuchAlgorithmException e) { + logger.warn("No SHA-512 algorithm available!"); + } + logger.debug("Calculated remember me key: {}", key); + this.key = key; + super.setKey(key); + } + + @Override + public String getKey() { + return this.key; + } + + /** + * Calculates the digital signature to be put in the cookie. Default value is + * SHA-512 ("username:tokenExpiryTime:password:key") + */ + @Override + protected String makeTokenSignature(long tokenExpiryTime, String username, String password) { + String data = username + ":" + tokenExpiryTime + ":" + password + ":" + getKey(); + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-512"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("No SHA-512 algorithm available!"); + } + + return new String(Hex.encode(digest.digest(data.getBytes()))); + } +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-mh8g-hprg-8363ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-5222ghsaADVISORY
- github.com/opencast/opencast/commit/1a7172c95af8d542a77ae5b153e4c834dd4788a6ghsax_refsource_MISCWEB
- github.com/opencast/opencast/security/advisories/GHSA-mh8g-hprg-8363ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.