All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.kafka.common.security.oauthbearer.OAuthBearerExtensionsValidatorCallback Maven / Gradle / Ivy

There is a newer version: 3.3.8
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache 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://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.apache.kafka.common.security.oauthbearer;

import org.apache.kafka.common.security.auth.SaslExtensions;

import javax.security.auth.callback.Callback;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static org.apache.kafka.common.utils.CollectionUtils.subtractMap;

/**
 * A {@code Callback} for use by the {@code SaslServer} implementation when it
 * needs to validate the SASL extensions for the OAUTHBEARER mechanism
 * Callback handlers should use the {@link #valid(String)}
 * method to communicate valid extensions back to the SASL server.
 * Callback handlers should use the
 * {@link #error(String, String)} method to communicate validation errors back to
 * the SASL Server.
 * As per RFC-7628 (https://tools.ietf.org/html/rfc7628#section-3.1), unknown extensions must be ignored by the server.
 * The callback handler implementation should simply ignore unknown extensions,
 * not calling {@link #error(String, String)} nor {@link #valid(String)}.
 * Callback handlers should communicate other problems by raising an {@code IOException}.
 * 

* The OAuth bearer token is provided in the callback for better context in extension validation. * It is very important that token validation is done in its own {@link OAuthBearerValidatorCallback} * irregardless of provided extensions, as they are inherently insecure. */ public class OAuthBearerExtensionsValidatorCallback implements Callback { private final OAuthBearerToken token; private final SaslExtensions inputExtensions; private final Map validatedExtensions = new HashMap<>(); private final Map invalidExtensions = new HashMap<>(); public OAuthBearerExtensionsValidatorCallback(OAuthBearerToken token, SaslExtensions extensions) { this.token = Objects.requireNonNull(token); this.inputExtensions = Objects.requireNonNull(extensions); } /** * @return {@link OAuthBearerToken} the OAuth bearer token of the client */ public OAuthBearerToken token() { return token; } /** * @return {@link SaslExtensions} consisting of the unvalidated extension names and values that were sent by the client */ public SaslExtensions inputExtensions() { return inputExtensions; } /** * @return an unmodifiable {@link Map} consisting of the validated and recognized by the server extension names and values */ public Map validatedExtensions() { return Collections.unmodifiableMap(validatedExtensions); } /** * @return An immutable {@link Map} consisting of the name->error messages of extensions which failed validation */ public Map invalidExtensions() { return Collections.unmodifiableMap(invalidExtensions); } /** * @return An immutable {@link Map} consisting of the extensions that have neither been validated nor invalidated */ public Map ignoredExtensions() { return Collections.unmodifiableMap(subtractMap(subtractMap(inputExtensions.map(), invalidExtensions), validatedExtensions)); } /** * Validates a specific extension in the original {@code inputExtensions} map * @param extensionName - the name of the extension which was validated */ public void valid(String extensionName) { if (!inputExtensions.map().containsKey(extensionName)) throw new IllegalArgumentException(String.format("Extension %s was not found in the original extensions", extensionName)); validatedExtensions.put(extensionName, inputExtensions.map().get(extensionName)); } /** * Set the error value for a specific extension key-value pair if validation has failed * * @param invalidExtensionName * the mandatory extension name which caused the validation failure * @param errorMessage * error message describing why the validation failed */ public void error(String invalidExtensionName, String errorMessage) { if (Objects.requireNonNull(invalidExtensionName).isEmpty()) throw new IllegalArgumentException("extension name must not be empty"); this.invalidExtensions.put(invalidExtensionName, errorMessage); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy