/*
* 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.nifi.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processor.util.StandardValidators;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* All processors and controller services that need properties for Kerberos
* Principal and Keytab should obtain them through this class by calling:
*
* KerberosProperties props =
* KerberosProperties.create(NiFiProperties.getInstance())
*
* The properties can be accessed from the resulting KerberosProperties
* instance.
*/
public class KerberosProperties {
private final File kerberosConfigFile;
private final Validator kerberosConfigValidator;
private final PropertyDescriptor kerberosPrincipal;
private final PropertyDescriptor kerberosKeytab;
/**
* Instantiate a KerberosProperties object but keep in mind it is
* effectively a singleton because the krb5.conf file needs to be set as a
* system property which this constructor will take care of.
*
* @param kerberosConfigFile file of krb5.conf
*/
public KerberosProperties(final File kerberosConfigFile) {
this.kerberosConfigFile = kerberosConfigFile;
this.kerberosConfigValidator = new Validator() {
@Override
public ValidationResult validate(String subject, String input, ValidationContext context) {
// Check that the Kerberos configuration is set
if (kerberosConfigFile == null) {
return new ValidationResult.Builder()
.subject(subject).input(input).valid(false)
.explanation("you are missing the nifi.kerberos.krb5.file property which "
+ "must be set in order to use Kerberos")
.build();
}
// Check that the Kerberos configuration is readable
if (!kerberosConfigFile.canRead()) {
return new ValidationResult.Builder().subject(subject).input(input).valid(false)
.explanation(String.format("unable to read Kerberos config [%s], please make sure the path is valid "
+ "and nifi has adequate permissions", kerberosConfigFile.getAbsoluteFile()))
.build();
}
return new ValidationResult.Builder().subject(subject).input(input).valid(true).build();
}
};
this.kerberosPrincipal = new PropertyDescriptor.Builder()
.name("Kerberos Principal")
.required(false)
.description("Kerberos principal to authenticate as. Requires nifi.kerberos.krb5.file to be set in your nifi.properties")
.addValidator(kerberosConfigValidator)
.build();
this.kerberosKeytab = new PropertyDescriptor.Builder()
.name("Kerberos Keytab").required(false)
.description("Kerberos keytab associated with the principal. Requires nifi.kerberos.krb5.file to be set in your nifi.properties")
.addValidator(StandardValidators.FILE_EXISTS_VALIDATOR)
.addValidator(kerberosConfigValidator)
.build();
}
public File getKerberosConfigFile() {
return kerberosConfigFile;
}
public Validator getKerberosConfigValidator() {
return kerberosConfigValidator;
}
public PropertyDescriptor getKerberosPrincipal() {
return kerberosPrincipal;
}
public PropertyDescriptor getKerberosKeytab() {
return kerberosKeytab;
}
public static List<ValidationResult> validatePrincipalAndKeytab(final String subject, final Configuration config, final String principal, final String keytab, final ComponentLog logger) {
final List<ValidationResult> results = new ArrayList<>();
// if security is enabled then the keytab and principal are required
final boolean isSecurityEnabled = SecurityUtil.isSecurityEnabled(config);
final boolean blankPrincipal = (principal == null || principal.isEmpty());
if (isSecurityEnabled && blankPrincipal) {
results.add(new ValidationResult.Builder()
.valid(false)
.subject(subject)
.explanation("Kerberos Principal must be provided when using a secure configuration")
.build());
}
final boolean blankKeytab = (keytab == null || keytab.isEmpty());
if (isSecurityEnabled && blankKeytab) {
results.add(new ValidationResult.Builder()
.valid(false)
.subject(subject)
.explanation("Kerberos Keytab must be provided when using a secure configuration")
.build());
}
if (!isSecurityEnabled && (!blankPrincipal || !blankKeytab)) {
logger.warn("Configuration does not have security enabled, Keytab and Principal will be ignored");
}
return results;
}
}