docs: private HashMap<String, String> getPropertyFromRequest(
              HashMap<String, String> tokens, HttpServletRequest request) {
          // Iterate through all of the other property keys looking for the first property
          // named like propname that has a value in the request
          HashMap<String, String> retHash = new HashMap<>();
  
          for (Map.Entry<String, String> entry : tokens.entrySet()) {
              String contextName = entry.getKey();
              String parmName = entry.getValue();
              String parmValue;
              if (request.getAttribute(parmName) != null) {
                  // Upstream components (like servlet filters) may supply information
                  // for the authentication process using request attributes.
                  try {
                      parmValue = (String) request.getAttribute(parmName);
                  } catch (ClassCastException cce) {
                      String msg = "The request attribute '" + parmName + "' must be a String.";
                      throw new RuntimeException(msg, cce);
                  }
              } else {
                  // If a configured parameter isn't provided by a request attribute,
                  // check request parameters (i.e. querystring, form fields).
                  parmValue = request.getParameter(parmName);
              }
              // null value causes exception in context.authentication
              // alternately we could just not set parm if value is null
              if ("password".equals(parmName)) {
                  // make sure we don't trim passwords, since they might have
                  // leading or trailing spaces
                  parmValue = (parmValue == null ? "" : parmValue);
              } else {
                  parmValue = (parmValue == null ? "" : parmValue).trim();
              }
  
              // The relationship between the way the properties are stored and the way
              // the subcontexts are named has to be closely looked at to make this work.
              // The keys are either "root" or the subcontext name that follows "root.". As
              // as example, the contexts ["root", "root.simple", "root.cas"] are represented
              // as ["root", "simple", "cas"].
              String key = (contextName.startsWith("root.") ? contextName.substring(5) : contextName);
              retHash.put(key, parmValue);
          }
          return (retHash);
      }