package com.thinkbiganalytics.nifi.security; /*- * #%L * thinkbig-nifi-security-api * %% * Copyright (C) 2017 ThinkBig Analytics * %% * Licensed 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. * #L% */ import org.apache.commons.lang3.Validate; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.security.UserGroupInformation; import org.apache.nifi.logging.ComponentLog; import java.io.IOException; /** * Provides synchronized access to UserGroupInformation to avoid multiple processors/services from * interfering with each other. */ public class SecurityUtil { /** * Initializes UserGroupInformation with the given Configuration and performs the login for the given principal * and keytab. All logins should happen through this class to ensure other threads are not concurrently modifying * UserGroupInformation. * * @param config the configuration instance * @param principal the principal to authenticate as * @param keyTab the keytab to authenticate with * @return the UGI for the given principal * @throws IOException if login failed */ public static synchronized UserGroupInformation loginKerberos(final Configuration config, final String principal, final String keyTab) throws IOException { Validate.notNull(config); Validate.notNull(principal); Validate.notNull(keyTab); config.set("hadoop.security.authentication", "Kerberos"); UserGroupInformation.setConfiguration(config); return UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal.trim(), keyTab.trim()); } /** * Initializes UserGroupInformation with the given Configuration and returns UserGroupInformation.getLoginUser(). * All logins should happen through this class to ensure other threads are not concurrently modifying * UserGroupInformation. * * @param config the configuration instance * @return the UGI for the given principal * @throws IOException if login failed */ public static synchronized UserGroupInformation loginSimple(final Configuration config) throws IOException { Validate.notNull(config); UserGroupInformation.setConfiguration(config); return UserGroupInformation.getLoginUser(); } /** * Initializes UserGroupInformation with the given Configuration and returns UserGroupInformation.isSecurityEnabled(). * * All checks for isSecurityEnabled() should happen through this method. * * @param config the given configuration * @return true if kerberos is enabled on the given configuration, false otherwise */ public static boolean isSecurityEnabled(final Configuration config) { Validate.notNull(config); return "kerberos".equalsIgnoreCase(config.get("hadoop.security.authentication")); } /** * Start a thread that periodically attempts to renew the current Kerberos user's ticket. * * Callers of this method should store the reference to the KerberosTicketRenewer and call stop() to stop the thread. * * @param id The unique identifier to use for the thread, can be the class name that started the thread (i.e. PutHDFS, etc) * @param ugi The current Kerberos user. * @param renewalPeriod The amount of time between attempting renewals. * @param logger The logger to use with in the renewer * @return the KerberosTicketRenewer Runnable */ public static KerberosTicketRenewer startTicketRenewalThread(final String id, final UserGroupInformation ugi, final long renewalPeriod, final ComponentLog logger) { final KerberosTicketRenewer renewer = new KerberosTicketRenewer(ugi, renewalPeriod, logger); final Thread t = new Thread(renewer); t.setName("Kerberos Ticket Renewal [" + id + "]"); t.start(); return renewer; } }