org.apache.ranger.plugin.util.RangerRESTClient.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ranger.plugin.util.RangerRESTClient.java

Source

/*
 * 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.plugin.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
import org.apache.ranger.authorization.hadoop.utils.RangerCredentialProvider;
import org.apache.ranger.authorization.utils.StringUtil;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.client.urlconnection.HTTPSProperties;

public class RangerRESTClient {
    private static final Log LOG = LogFactory.getLog(RangerRESTClient.class);

    public static final String RANGER_PROP_POLICYMGR_URL = "ranger.service.store.rest.url";
    public static final String RANGER_PROP_POLICYMGR_SSLCONFIG_FILENAME = "ranger.service.store.rest.ssl.config.file";

    public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE = "xasecure.policymgr.clientssl.keystore";
    public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE = "xasecure.policymgr.clientssl.keystore.type";
    public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL = "xasecure.policymgr.clientssl.keystore.credential.file";
    public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL_ALIAS = "sslKeyStore";
    public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE_DEFAULT = "jks";

    public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE = "xasecure.policymgr.clientssl.truststore";
    public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE = "xasecure.policymgr.clientssl.truststore.type";
    public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL = "xasecure.policymgr.clientssl.truststore.credential.file";
    public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL_ALIAS = "sslTrustStore";
    public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE_DEFAULT = "jks";

    public static final String RANGER_SSL_KEYMANAGER_ALGO_TYPE = "SunX509";
    public static final String RANGER_SSL_TRUSTMANAGER_ALGO_TYPE = "SunX509";
    public static final String RANGER_SSL_CONTEXT_ALGO_TYPE = "SSL";

    private String mUrl = null;
    private String mSslConfigFileName = null;
    private String mUsername = null;
    private String mPassword = null;
    private boolean mIsSSL = false;

    private String mKeyStoreURL = null;
    private String mKeyStoreAlias = null;
    private String mKeyStoreFile = null;
    private String mKeyStoreType = null;
    private String mTrustStoreURL = null;
    private String mTrustStoreAlias = null;
    private String mTrustStoreFile = null;
    private String mTrustStoreType = null;

    private Gson gsonBuilder = null;
    private volatile Client client = null;

    private int mRestClientConnTimeOutMs;
    private int mRestClientReadTimeOutMs;

    public RangerRESTClient() {
        this(RangerConfiguration.getInstance().get(RANGER_PROP_POLICYMGR_URL),
                RangerConfiguration.getInstance().get(RANGER_PROP_POLICYMGR_SSLCONFIG_FILENAME));
    }

    public RangerRESTClient(String url, String sslConfigFileName) {
        mUrl = url;
        mSslConfigFileName = sslConfigFileName;

        init();
    }

    public String getUrl() {
        return mUrl;
    }

    public void setUrl(String url) {
        this.mUrl = url;
    }

    public String getUsername() {
        return mUsername;
    }

    public String getPassword() {
        return mPassword;
    }

    public int getRestClientConnTimeOutMs() {
        return mRestClientConnTimeOutMs;
    }

    public void setRestClientConnTimeOutMs(int mRestClientConnTimeOutMs) {
        this.mRestClientConnTimeOutMs = mRestClientConnTimeOutMs;
    }

    public int getRestClientReadTimeOutMs() {
        return mRestClientReadTimeOutMs;
    }

    public void setRestClientReadTimeOutMs(int mRestClientReadTimeOutMs) {
        this.mRestClientReadTimeOutMs = mRestClientReadTimeOutMs;
    }

    public void setBasicAuthInfo(String username, String password) {
        mUsername = username;
        mPassword = password;
    }

    public WebResource getResource(String relativeUrl) {
        WebResource ret = getClient().resource(getUrl() + relativeUrl);

        return ret;
    }

    public String toJson(Object obj) {
        return gsonBuilder.toJson(obj);
    }

    public <T> T fromJson(String json, Class<T> cls) {
        return gsonBuilder.fromJson(json, cls);
    }

    public Client getClient() {
        // result saves on access time when client is built at the time of the call
        Client result = client;
        if (result == null) {
            synchronized (this) {
                result = client;
                if (result == null) {
                    client = result = buildClient();
                }
            }
        }

        return result;
    }

    private Client buildClient() {
        Client client = null;

        if (mIsSSL) {
            KeyManager[] kmList = getKeyManagers();
            TrustManager[] tmList = getTrustManagers();
            SSLContext sslContext = getSSLContext(kmList, tmList);
            ClientConfig config = new DefaultClientConfig();

            config.getClasses().add(JacksonJsonProvider.class); // to handle List<> unmarshalling

            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return session.getPeerHost().equals(urlHostName);
                }
            };

            config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
                    new HTTPSProperties(hv, sslContext));

            client = Client.create(config);
        }

        if (client == null) {
            ClientConfig config = new DefaultClientConfig();

            config.getClasses().add(JacksonJsonProvider.class); // to handle List<> unmarshalling

            client = Client.create(config);
        }

        if (!StringUtils.isEmpty(mUsername) && !StringUtils.isEmpty(mPassword)) {
            client.addFilter(new HTTPBasicAuthFilter(mUsername, mPassword));
        }

        // Set Connection Timeout and ReadTime for the PolicyRefresh
        client.setConnectTimeout(mRestClientConnTimeOutMs);
        client.setReadTimeout(mRestClientReadTimeOutMs);

        return client;
    }

    private void init() {
        try {
            gsonBuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").setPrettyPrinting()
                    .create();
        } catch (Throwable excp) {
            LOG.fatal("RangerRESTClient.init(): failed to create GsonBuilder object", excp);
        }

        mIsSSL = StringUtil.containsIgnoreCase(mUrl, "https");

        InputStream in = null;

        try {
            Configuration conf = new Configuration();

            in = getFileInputStream(mSslConfigFileName);

            if (in != null) {
                conf.addResource(in);
            }

            mKeyStoreURL = conf.get(RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL);
            mKeyStoreAlias = RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL_ALIAS;
            mKeyStoreType = conf.get(RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE,
                    RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE_DEFAULT);
            mKeyStoreFile = conf.get(RANGER_POLICYMGR_CLIENT_KEY_FILE);

            mTrustStoreURL = conf.get(RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL);
            mTrustStoreAlias = RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL_ALIAS;
            mTrustStoreType = conf.get(RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE,
                    RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE_DEFAULT);
            mTrustStoreFile = conf.get(RANGER_POLICYMGR_TRUSTSTORE_FILE);
        } catch (IOException ioe) {
            LOG.error("Unable to load SSL Config FileName: [" + mSslConfigFileName + "]", ioe);
        } finally {
            close(in, mSslConfigFileName);
        }
    }

    private KeyManager[] getKeyManagers() {
        KeyManager[] kmList = null;

        String keyStoreFilepwd = getCredential(mKeyStoreURL, mKeyStoreAlias);

        if (!StringUtil.isEmpty(mKeyStoreFile) && !StringUtil.isEmpty(keyStoreFilepwd)) {
            InputStream in = null;

            try {
                in = getFileInputStream(mKeyStoreFile);

                if (in != null) {
                    KeyStore keyStore = KeyStore.getInstance(mKeyStoreType);

                    keyStore.load(in, keyStoreFilepwd.toCharArray());

                    KeyManagerFactory keyManagerFactory = KeyManagerFactory
                            .getInstance(RANGER_SSL_KEYMANAGER_ALGO_TYPE);

                    keyManagerFactory.init(keyStore, keyStoreFilepwd.toCharArray());

                    kmList = keyManagerFactory.getKeyManagers();
                } else {
                    LOG.error("Unable to obtain keystore from file [" + mKeyStoreFile + "]");
                }
            } catch (KeyStoreException e) {
                LOG.error("Unable to obtain from KeyStore", e);
            } catch (NoSuchAlgorithmException e) {
                LOG.error("SSL algorithm is available in the environment", e);
            } catch (CertificateException e) {
                LOG.error("Unable to obtain the requested certification ", e);
            } catch (FileNotFoundException e) {
                LOG.error("Unable to find the necessary SSL Keystore and TrustStore Files", e);
            } catch (IOException e) {
                LOG.error("Unable to read the necessary SSL Keystore and TrustStore Files", e);
            } catch (UnrecoverableKeyException e) {
                LOG.error("Unable to recover the key from keystore", e);
            } finally {
                close(in, mKeyStoreFile);
            }
        }

        return kmList;
    }

    private TrustManager[] getTrustManagers() {
        TrustManager[] tmList = null;

        String trustStoreFilepwd = getCredential(mTrustStoreURL, mTrustStoreAlias);

        if (!StringUtil.isEmpty(mTrustStoreFile) && !StringUtil.isEmpty(trustStoreFilepwd)) {
            InputStream in = null;

            try {
                in = getFileInputStream(mTrustStoreFile);

                if (in != null) {
                    KeyStore trustStore = KeyStore.getInstance(mTrustStoreType);

                    trustStore.load(in, trustStoreFilepwd.toCharArray());

                    TrustManagerFactory trustManagerFactory = TrustManagerFactory
                            .getInstance(RANGER_SSL_TRUSTMANAGER_ALGO_TYPE);

                    trustManagerFactory.init(trustStore);

                    tmList = trustManagerFactory.getTrustManagers();
                } else {
                    LOG.error("Unable to obtain keystore from file [" + mTrustStoreFile + "]");
                }
            } catch (KeyStoreException e) {
                LOG.error("Unable to obtain from KeyStore", e);
            } catch (NoSuchAlgorithmException e) {
                LOG.error("SSL algorithm is available in the environment", e);
            } catch (CertificateException e) {
                LOG.error("Unable to obtain the requested certification ", e);
            } catch (FileNotFoundException e) {
                LOG.error("Unable to find the necessary SSL Keystore and TrustStore Files", e);
            } catch (IOException e) {
                LOG.error("Unable to read the necessary SSL Keystore and TrustStore Files", e);
            } finally {
                close(in, mTrustStoreFile);
            }
        }

        return tmList;
    }

    private SSLContext getSSLContext(KeyManager[] kmList, TrustManager[] tmList) {
        try {
            if (tmList != null) {
                SSLContext sslContext = SSLContext.getInstance(RANGER_SSL_CONTEXT_ALGO_TYPE);

                sslContext.init(kmList, tmList, new SecureRandom());

                return sslContext;
            }
        } catch (NoSuchAlgorithmException e) {
            LOG.error("SSL algorithm is available in the environment", e);
        } catch (KeyManagementException e) {
            LOG.error("Unable to initials the SSLContext", e);
        } catch (Exception e) {
            LOG.error("Unable to initialize the SSLContext", e);
        }
        return null;
    }

    private String getCredential(String url, String alias) {
        char[] credStr = RangerCredentialProvider.getInstance().getCredentialString(url, alias);

        return credStr == null ? null : new String(credStr);
    }

    private InputStream getFileInputStream(String fileName) throws IOException {
        InputStream in = null;

        if (!StringUtil.isEmpty(fileName)) {
            File f = new File(fileName);

            if (f.exists()) {
                in = new FileInputStream(f);
            } else {
                in = ClassLoader.getSystemResourceAsStream(fileName);
            }
        }

        return in;
    }

    private void close(InputStream str, String filename) {
        if (str != null) {
            try {
                str.close();
            } catch (IOException excp) {
                LOG.error("Error while closing file: [" + filename + "]", excp);
            }
        }
    }
}