Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Adjusted/added convenience methods on SubstitutableModuleOptions and SubstitutableModuleOptionsCallbackHandler

...

Code Block
languagejava
titleorg.apache.kafka.common.security.oauthbearer.smo.SubstitutableModuleOptions
collapsetrue
package org.apache.kafka.common.security.oauthbearer.smo;

/**
 * Holds state regarding which {@code LoginModule} <a href=
 * "https://docs.oracle.com/javase/9/docs/api/javax/security/auth/login/Configuration.html">module
 * options</a> have been substituted. Instances of this class are thread-safe.
 *
 * @see SubstitutableModuleOptionsCallbackHandler
 * @see SubstitutableModuleOptionsCallback
 */
public class SubstitutableModuleOptions {
    /**
     * Constructor
     *
     * @param moduleOptionsMap
     *            the mandatory map representation of the <a href=
     *            "https://docs.oracle.com/javase/9/docs/api/javax/security/auth/login/Configuration.html">module
     *            options</a>
     */
    public SubstitutableModuleOptions(Map<String, String> moduleOptionsMap) {
        this.moduleOptionsMap = Collections.unmodifiableMap(Objects.requireNonNull(moduleOptionsMap));
    }

    /**
     * Return (an unmodifiable copy of) the original module options map provided
     * during construction
     *
     * @return (an unmodifiable copy of) the original module options map provided
     *         during construction
     */
    public Map<String, String> moduleOptionsMap() {
        return moduleOptionsMap;
    }
 
    /**
     * Convenience method to indicate if a particular option name exists, returning
     * true if it does, otherwise false
     *
     * @param optionName
     *            the mandatory option name
     * @return true if the indicated option exists, otherwise false
     */
    boolean optionExists(String optionName) {
        return moduleOptionsMap.containsKey(Objects.requireNonNull(optionName));
    }
 
    /**
     * Return an unmodifiable map identifying which module options have been
     * processed for substitution and the resulting value after substitution (if
     * any) was applied. A module option is guaranteed to have been processed for
     * substitution and its name will appear as a key in the returned map only after
     * {@link #setSubstitutionValue(String, String)} or
     * {@link #setSubstitutionValue(String, Password)} is called.
     *
     * @return an unmodifiable map identifying which module options have been
     *         processed for substitution and the resulting value after substitution
     *         (if any) was applied
     */
    public Map<String, Object> moduleOptionSubstitutionState() {
        return Collections.unmodifiableMap(moduleOptionSubstitutionState);
    }
 
    /**
     * Identify that the option with the given name has had substitution performed
     * for it resulting in the given non-password value. This method can be
     * successfully invoked (and is idempotent) only if invoked before
     * {@link #setSubstitutionValue(String, Password)}; the option value cannot be
     * changed.
     *
     * @param optionName
     *            the mandatory option name, which must exist in the map returned by
     *            {@link #moduleOptionsMap()}
     * @param substitutionValue
     *            the mandatory substitution value to set
     */
    public void setSubstitutionValue(String optionName, String substitutionValue) {
        setSubstitutionValueInternal(Objects.requireNonNull(optionName), Objects.requireNonNull(substitutionValue));
    }
 
    /**
     * Identify that the option with the given name has had substitution performed
     * for it resulting in the given password-related value. This method can be
     * successfully invoked (and is idempotent) only if invoked before
     * {@link #setSubstitutionValue(String, String)}; the option value cannot be
     * changed.
     *
     * @param optionName
     *            the mandatory option name, which must exist in the map returned by
     *            {@link #moduleOptionsMap()}
     * @param substitutionValue
     *            the mandatory substitution value to set
     */
    public void setSubstitutionValue(String optionName, Password substitutionValue) {
        setSubstitutionValueInternal(Objects.requireNonNull(optionName), Objects.requireNonNull(substitutionValue));
    }
 
    // etc..
}

...

Code Block
languagejava
titleorg.apache.kafka.common.security.oauthbearer.smo.SubstitutableModuleOptionsCallbackHandler
collapsetrue
package org.apache.kafka.common.security.oauthbearer.smo;

/**
 * A {@code CallbackHandler} that handles introspection requests against a JAAS
 * configuration
 *
 * @see SubstitutableModuleOptionsCallback
 * @see SubstitutableModuleOptions
 */
public class SubstitutableModuleOptionsCallbackHandler implements AuthenticateCallbackHandler {
    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            if (callback instanceof SubstitutableModuleOptionsCallback) {
                SubstitutableModuleOptionsCallback substitutableModuleOptionsCallback = (SubstitutableModuleOptionsCallback) callback;
                SubstitutableModuleOptionsObject substitutableModuleOptionssubstitutionValue = substitutableModuleOptionsCallbackgetSubstitutionValue(
                        substitutableModuleOptionsCallback.substitutableModuleOptions();,
                     String optionName = substitutableModuleOptionsCallback.optionName();,
                     boolean optionRequiredToExist = substitutableModuleOptionsCallback.optionRequiredToExist());
                // depend on  boolean optionExists = substitutableModuleOptions.moduleOptionsMap().containsKey(optionName);idempotence here because the substitution value has already been
                if (!optionExists) {
    // set on the underlying SubstitutableModuleOptions instance
                if (!optionRequiredToExistsubstitutionValue instanceof String)
                    substitutableModuleOptionsCallback.setSubstitutionValue((String) substitutionValue);
   continue;
             else if (substitutionValue instanceof Password)
      else
              substitutableModuleOptionsCallback.setSubstitutionValue((Password) substitutionValue);
           throw new} IOException(Stringelse
                throw new UnsupportedCallbackException(callback,
                 .format("The requested option was required to exist but does not String.format("Unrecognized Callback type: %s", optionNamecallback.getClass().getName()));
        }
    }
 
    }/**
     * Return the server configuration provided during
     Object* substitutionValue = getSubstitutionValue(substitutableModuleOptions{@link #configure(Map, optionNameString,
 List)}, if any, otherwise null
     *
     * @return the server configuration provided during
   new HashSet<String>());
 *         {@link #configure(Map,    String, List)}, if (substitutionValueany, instanceofotherwise String)null
     */
    public Map<String, ?> serverConfig() {
        substitutableModuleOptionsCallback.setSubstitutionValue((String) substitutionValue)return serverConfig;
    }

    /**
     * Return the else
SASL mechanism provided during
     * {@link #configure(Map, String, List)}, if any, otherwise null
    substitutableModuleOptionsCallback.setSubstitutionValue((Password) substitutionValue); *
     * @return the SASL mechanism provided  } elseduring
     *           throw new UnsupportedCallbackException(callback,
      {@link #configure(Map, String, List)}, if any, otherwise null
     */
    public String mechanism() {
      String.format("Unrecognized Callback type: %s", callback.getClass().getName()));
    return mechanism;
    }
    }
 
    /**
     * Return the server configurationJAAS login module configurations provided during
     * {@link #configure(Map, String, List)}, if any, otherwise null
     *
     * @return the JAAS login servermodule configurationconfigurations provided during
     *         {@link #configure(Map, String, List)}, if any, otherwise null
     */
    public Map<String, ?> serverConfigList<AppConfigurationEntry> jaasConfigEntries() {
        return serverConfigjaasConfigEntries;
    }
 
    /**
     * ReturnConvenience themethod SASLto mechanismperform providedsubstitution during
without using callbacks and a
 * {@link #configure(Map, String, List)}, if any, otherwise null * callback handler.
     *
     * @return@param thesubstitutableModuleOptions
 SASL mechanism provided during
 *    *        the {@link #configure(Map, String, List)}, if any, otherwise null
mandatory substitutable module options to query
     * @param */optionName
    public String* mechanism() {
        return mechanism;
 the mandatory requested }option

     /** @param optionRequiredToExist
     * Return the JAAS login module configurations provided during     if true then the requested option is required to exist
     * @return the given option value, after any required substitution is applied,
     *         or null if the option does not exist and it was not required to exist
     * @throws IOException
     *             if a required substitution cannot be performed, including if the
     *             given -- or another -- required option does not exist
     * {@link #configure(Map/
    public static Object getSubstitutionValue(SubstitutableModuleOptions substitutableModuleOptions, String optionName, List)}, if any, otherwise null
            boolean optionRequiredToExist) throws IOException {
        if (!substitutableModuleOptions.optionExists(optionName)) {
            if (!optionRequiredToExist)
     *
     * @return the JAAS login module configurations provided duringreturn null;
     *       throw  {@link #configure(Map, String, List)}, if any, otherwise nullnew IOException(String.format("Mandatory option does not exist: %s", optionName));
     */
   }
 public List<AppConfigurationEntry> jaasConfigEntries() {
    return getSubstitutionValue(substitutableModuleOptions, optionName,  return jaasConfigEntriesnew HashSet<String>());
    }
 
    /**
     * Convenience method to perform substitution without using callbacks and a
     * callback handler.
     *
     * @param substitutableModuleOptions
     *            the mandatory substitutable module options to query
     * @param optionName
     *            the mandatory requested option
     * @param optionRequiredToExist
     *            if true, andthen the requested option does not exist, then an
     *            exception is raised; if false, and the requested option does not
     *            exist, then the empty string is returned.required to exist
     * @return the given option valuetext, after any required substitution is applied,, or
     *         or the empty stringnull if the option does not exist and it was not
     *         required to exist
     * @throws IOException
     *             if a required substitution cannot be performed, (including if athe
     *             given -- or another -- required option does not exist)
     */
    public static ObjectString getSubstitutionValuegetSubstitutionText(SubstitutableModuleOptions substitutableModuleOptions, String optionName,
            boolean optionRequiredToExist) throws IOException {
        booleanObject optionExistssubstitutionValue = substitutableModuleOptions.moduleOptionsMap().containsKey(optionNamegetSubstitutionValue(substitutableModuleOptions, optionName, optionRequiredToExist);
        if (!optionExists) {
            if (!optionRequiredToExistsubstitutionValue instanceof String)
                return "";
            else
                throw new IOException(
                        String.format("The requested option was required to exist but does not: %s", optionName));
) substitutionValue;
        if (substitutionValue instanceof }Password)
        return  getSubstitutionValue(substitutableModuleOptions, optionName, newreturn HashSet<String>((Password) substitutionValue).value();
        return null;
    }
 
    /*
     * Handle substitution, dealing with circular references, constraints, etc. It
     * is an error if the indicated option does not exist.
     */
    private static Object getSubstitutionValue(SubstitutableModuleOptions substitutableModuleOptions,
 String optionName,
          String optionNameRequiredToExist, HashSet<String> optionsSeen) throws IOException {
        // etc...
    }
 
    // etc...
}

...

Code Block
languagejava
titleRetrieving Values via a Callback
SubstitutableModuleOptions options = new SubstitutableModuleOptions(moduleOptionsMap);
boolean requiredToExist = true;
SubstitutableModuleOptionsCallback callback = new SubstitutableModuleOptionsCallback(options, "thePassword", requiredToExist);
CallbackHandler callbackHandler = new SubstitutableModuleOptionsCallbackHandler()
callbackHandler.handle(new Callback[] {callback});
String thePassword = callback.substitutionText();

Alternatively, there is a convenience method that allows us to avoid using a callback if we wish:

Code Block
languagejava
titleRetrieving Values without a Callback
SubstitutableModuleOptions options = new SubstitutableModuleOptions(moduleOptionsMap);
boolean requiredToExist = true;
String thePassword = SubstitutableModuleOptionsCallbackHandler.getSubstitutionText(substitutableModuleOptions,
        "thePassword", requiredToExist);

The initial set of supported substitution types and their specifiable constraints are as follows:

...