/*
* 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.authenticator;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import org.apache.kafka.common.config.types.Password;
import org.apache.kafka.common.security.plain.PlainLoginModule;
import org.apache.kafka.common.security.scram.ScramLoginModule;
import org.apache.kafka.common.security.scram.ScramMechanism;
public class TestJaasConfig extends Configuration {
static final String LOGIN_CONTEXT_CLIENT = "KafkaClient";
static final String LOGIN_CONTEXT_SERVER = "KafkaServer";
static final String USERNAME = "myuser";
static final String PASSWORD = "mypassword";
private Map<String, AppConfigurationEntry[]> entryMap = new HashMap<>();
public static TestJaasConfig createConfiguration(String clientMechanism, List<String> serverMechanisms) {
TestJaasConfig config = new TestJaasConfig();
config.createOrUpdateEntry(LOGIN_CONTEXT_CLIENT, loginModule(clientMechanism), defaultClientOptions());
for (String mechanism : serverMechanisms) {
config.addEntry(LOGIN_CONTEXT_SERVER, loginModule(mechanism), defaultServerOptions(mechanism));
}
Configuration.setConfiguration(config);
return config;
}
public static Password jaasConfigProperty(String mechanism, String username, String password) {
return new Password(loginModule(mechanism) + " required username=" + username + " password=" + password + ";");
}
public void setPlainClientOptions(String clientUsername, String clientPassword) {
Map<String, Object> options = new HashMap<>();
if (clientUsername != null)
options.put("username", clientUsername);
if (clientPassword != null)
options.put("password", clientPassword);
createOrUpdateEntry(LOGIN_CONTEXT_CLIENT, PlainLoginModule.class.getName(), options);
}
public void createOrUpdateEntry(String name, String loginModule, Map<String, Object> options) {
AppConfigurationEntry entry = new AppConfigurationEntry(loginModule, LoginModuleControlFlag.REQUIRED, options);
entryMap.put(name, new AppConfigurationEntry[] {entry});
}
public void addEntry(String name, String loginModule, Map<String, Object> options) {
AppConfigurationEntry entry = new AppConfigurationEntry(loginModule, LoginModuleControlFlag.REQUIRED, options);
AppConfigurationEntry[] existing = entryMap.get(name);
AppConfigurationEntry[] newEntries = existing == null ? new AppConfigurationEntry[1] : Arrays.copyOf(existing, existing.length + 1);
newEntries[newEntries.length - 1] = entry;
entryMap.put(name, newEntries);
}
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
return entryMap.get(name);
}
private static String loginModule(String mechanism) {
String loginModule;
switch (mechanism) {
case "PLAIN":
loginModule = PlainLoginModule.class.getName();
break;
case "DIGEST-MD5":
loginModule = TestDigestLoginModule.class.getName();
break;
default:
if (ScramMechanism.isScram(mechanism))
loginModule = ScramLoginModule.class.getName();
else
throw new IllegalArgumentException("Unsupported mechanism " + mechanism);
}
return loginModule;
}
public static Map<String, Object> defaultClientOptions() {
Map<String, Object> options = new HashMap<>();
options.put("username", USERNAME);
options.put("password", PASSWORD);
return options;
}
public static Map<String, Object> defaultServerOptions(String mechanism) {
Map<String, Object> options = new HashMap<>();
switch (mechanism) {
case "PLAIN":
case "DIGEST-MD5":
options.put("user_" + USERNAME, PASSWORD);
break;
default:
if (!ScramMechanism.isScram(mechanism))
throw new IllegalArgumentException("Unsupported mechanism " + mechanism);
}
return options;
}
}