org.apache.kafka.common.security.auth.SaslExtensions Maven / Gradle / Ivy
/*
* 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.auth;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import javax.security.auth.Subject;
/**
* A simple immutable value object class holding customizable SASL extensions.
*
*
*
* Note on object identity and equality: SaslExtensions
intentionally
* overrides the standard {@link #equals(Object)} and {@link #hashCode()} methods calling their
* respective {@link Object#equals(Object)} and {@link Object#hashCode()} implementations. In so
* doing, it provides equality only via reference identity and will not base equality on
* the underlying values of its {@link #extensionsMap extensions map}.
*
*
*
* The reason for this approach to equality is based off of the manner in which
* credentials are stored in a {@link Subject}. SaslExtensions
are added to and
* removed from a {@link Subject} via its {@link Subject#getPublicCredentials() public credentials}.
* The public credentials are stored in a {@link Set} in the {@link Subject}, so object equality
* therefore becomes a concern. With shallow, reference-based equality, distinct
* SaslExtensions
instances with the same map values can be considered unique. This is
* critical to operations like token refresh.
*
* See KAFKA-14062 for more detail.
*/
public class SaslExtensions {
private final Map extensionsMap;
public SaslExtensions(Map extensionsMap) {
this.extensionsMap = Collections.unmodifiableMap(new HashMap<>(extensionsMap));
}
/**
* Returns an immutable map of the extension names and their values
*/
public Map map() {
return extensionsMap;
}
/**
* Creates an "empty" instance indicating no SASL extensions. Do not cache the result of
* this method call for use by multiple {@link Subject}s as the references need to be
* unique.
*
*
*
* See the class-level documentation for details.
* @return Unique, but empty, SaslExtensions
instance
*/
@SuppressWarnings("unchecked")
public static SaslExtensions empty() {
// It's ok to re-use the EMPTY_MAP instance as the object equality is on the outer
// SaslExtensions reference.
return new SaslExtensions(Collections.EMPTY_MAP);
}
/**
* Implements equals using the reference comparison implementation from
* {@link Object#equals(Object)}.
*
*
*
* See the class-level documentation for details.
*
* @param o Other object to compare
* @return True if o == this
*/
@Override
public final boolean equals(Object o) {
return super.equals(o);
}
/**
* Implements hashCode
using the native implementation from
* {@link Object#hashCode()}.
*
*
*
* See the class-level documentation for details.
*
* @return Hash code of instance
*/
@Override
public final int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return new StringJoiner(", ", SaslExtensions.class.getSimpleName() + "[", "]")
.add("extensionsMap=" + extensionsMap)
.toString();
}
}