/* * 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.ranger.authentication; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.security.KeyStore; import java.security.SecureRandom; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import org.apache.log4j.Logger; import org.apache.ranger.credentialapi.CredentialReader; import org.apache.ranger.plugin.util.XMLUtils; import org.apache.ranger.usergroupsync.UserGroupSync; public class UnixAuthenticationService { private static final Logger LOG = Logger.getLogger(UnixAuthenticationService.class); private static final String serviceName = "UnixAuthenticationService"; private static final String SSL_ALGORITHM = "TLS"; private static final String REMOTE_LOGIN_AUTH_SERVICE_PORT_PARAM = "ranger.usersync.port"; private static final String SSL_KEYSTORE_PATH_PARAM = "ranger.usersync.keystore.file"; private static final String SSL_TRUSTSTORE_PATH_PARAM = "ranger.usersync.truststore.file"; private static final String SSL_KEYSTORE_PATH_PASSWORD_ALIAS = "usersync.ssl.key.password"; private static final String SSL_TRUSTSTORE_PATH_PASSWORD_ALIAS = "usersync.ssl.truststore.password"; private static final String CRED_VALIDATOR_PROG = "ranger.usersync.passwordvalidator.path"; private static final String ADMIN_USER_LIST_PARAM = "admin.users"; private static final String ADMIN_ROLE_LIST_PARAM = "admin.roleNames"; private static final String SSL_ENABLED_PARAM = "ranger.usersync.ssl"; private static final String CREDSTORE_FILENAME_PARAM = "ranger.usersync.credstore.filename"; private String keyStorePath; private String keyStorePathPassword; private String trustStorePath; private String trustStorePathPassword; private List<String> adminUserList = new ArrayList<String>(); private String adminRoleNames; private int portNum; private boolean SSLEnabled = false; static private boolean enableUnixAuth = false; private static final String[] UGSYNC_CONFIG_XML_FILES = { "ranger-ugsync-default.xml", "ranger-ugsync-site.xml" }; public static void main(String[] args) { if (args.length > 0) { for (String s : args) { if ("-enableUnixAuth".equalsIgnoreCase(s)) { enableUnixAuth = true; break; } } } UnixAuthenticationService service = new UnixAuthenticationService(); service.run(); } public UnixAuthenticationService() { } public void run() { try { LOG.info("Starting User Sync Service!"); startUnixUserGroupSyncProcess(); Thread.sleep(5000); if (enableUnixAuth) { LOG.info("Enabling Unix Auth Service!"); init(); startService(); } else { LOG.info("Unix Auth Service Disabled!"); } } catch(Throwable t) { LOG.error("ERROR: Service: " + serviceName , t); } finally { LOG.info("Service: " + serviceName + " - STOPPED."); } } private void startUnixUserGroupSyncProcess() { // // Start the synchronization service ... // UserGroupSync syncProc = new UserGroupSync(); Thread newSyncProcThread = new Thread(syncProc); newSyncProcThread.setName("UnixUserSyncThread"); newSyncProcThread.setDaemon(false); newSyncProcThread.start(); } //TODO: add more validation code private void init() throws Throwable { Properties prop = new Properties(); for (String fn : UGSYNC_CONFIG_XML_FILES ) { XMLUtils.loadConfig(fn, prop); } String credStoreFileName = prop.getProperty(CREDSTORE_FILENAME_PARAM); keyStorePath = prop.getProperty(SSL_KEYSTORE_PATH_PARAM); if (credStoreFileName == null) { throw new RuntimeException("Credential file is not defined. param = [" + CREDSTORE_FILENAME_PARAM + "]"); } File credFile = new File(credStoreFileName); if (! credFile.exists()) { throw new RuntimeException("Credential file [" + credStoreFileName + "]: does not exists." ); } if ( ! credFile.canRead() ) { throw new RuntimeException("Credential file [" + credStoreFileName + "]: can not be read." ); } keyStorePathPassword = CredentialReader.getDecryptedString(credStoreFileName, SSL_KEYSTORE_PATH_PASSWORD_ALIAS); trustStorePathPassword = CredentialReader.getDecryptedString(credStoreFileName,SSL_TRUSTSTORE_PATH_PASSWORD_ALIAS); trustStorePath = prop.getProperty(SSL_TRUSTSTORE_PATH_PARAM); portNum = Integer.parseInt(prop.getProperty(REMOTE_LOGIN_AUTH_SERVICE_PORT_PARAM)); String validatorProg = prop.getProperty(CRED_VALIDATOR_PROG); if (validatorProg != null) { PasswordValidator.setValidatorProgram(validatorProg); } String adminUsers = prop.getProperty(ADMIN_USER_LIST_PARAM); if (adminUsers != null && adminUsers.trim().length() > 0) { for(String u : adminUsers.split(",")) { LOG.info("Adding Admin User:" + u.trim()); adminUserList.add(u.trim()); } PasswordValidator.setAdminUserList(adminUserList); } adminRoleNames = prop.getProperty(ADMIN_ROLE_LIST_PARAM); if (adminRoleNames != null) { LOG.info("Adding Admin Group:" + adminRoleNames); PasswordValidator.setAdminRoleNames(adminRoleNames); } String SSLEnabledProp = prop.getProperty(SSL_ENABLED_PARAM); SSLEnabled = (SSLEnabledProp != null && (SSLEnabledProp.equalsIgnoreCase("true"))); // LOG.info("Key:" + keyStorePath); // LOG.info("KeyPassword:" + keyStorePathPassword); // LOG.info("TrustStore:" + trustStorePath); // LOG.info("PortNum:" + portNum); // LOG.info("ValidatorProg:" + validatorProg); } public void startService() throws Throwable { SSLContext context = SSLContext.getInstance(SSL_ALGORITHM); KeyManager[] km = null; if (keyStorePath != null && ! keyStorePath.isEmpty()) { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream in = null; in = getFileInputStream(keyStorePath); try { if (keyStorePathPassword == null) { keyStorePathPassword = ""; } ks.load(in, keyStorePathPassword.toCharArray()); } finally { if (in != null) { in.close(); } } KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, keyStorePathPassword.toCharArray()); km = kmf.getKeyManagers(); } TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore trustStoreKeyStore = null; if (trustStorePath != null && ! trustStorePath.isEmpty()) { trustStoreKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream in = null; in = getFileInputStream(trustStorePath); try { if (trustStorePathPassword == null) { trustStorePathPassword = ""; } trustStoreKeyStore.load(in, trustStorePathPassword.toCharArray()); } finally { if (in != null) { in.close(); } } } trustManagerFactory.init(trustStoreKeyStore); TrustManager[] tm = trustManagerFactory.getTrustManagers(); SecureRandom random = new SecureRandom(); context.init(km, tm, random); SSLServerSocketFactory sf = context.getServerSocketFactory(); ServerSocket socket = (SSLEnabled ? sf.createServerSocket(portNum) : new ServerSocket(portNum) ); if (SSLEnabled) { SSLServerSocket secureSocket = (SSLServerSocket) socket; String[] protocols = secureSocket.getEnabledProtocols(); Set<String> allowedProtocols = new HashSet<String>(); for(String ep : protocols) { if (! ep.toUpperCase().startsWith("SSLV3")) { LOG.info("Enabling Protocol: [" + ep + "]"); allowedProtocols.add(ep); } else { LOG.info("Disabling Protocol: [" + ep + "]"); } } if (!allowedProtocols.isEmpty()) { secureSocket.setEnabledProtocols(allowedProtocols.toArray(new String[0])); } } Socket client = null; try { while ( (client = socket.accept()) != null ) { Thread clientValidatorThread = new Thread(new PasswordValidator(client)); clientValidatorThread.start(); } } catch (IOException e) { socket.close(); throw(e); } } private InputStream getFileInputStream(String path) throws FileNotFoundException { InputStream ret = null; File f = new File(path); if (f.exists()) { ret = new FileInputStream(f); } else { ret = getClass().getResourceAsStream(path); if (ret == null) { ret = getClass().getResourceAsStream(File.separator + path); } } return ret; } }