org.apache.sqoop.connector.hdfs.security.SecurityUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sqoop.connector.hdfs.security.SecurityUtils.java

Source

/*
 * Copyright (C) 2016 Stratio (http://stratio.com)
 *
 * 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.
 */
package org.apache.sqoop.connector.hdfs.security;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.security.TokenCache;
import org.apache.hadoop.security.Credentials;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.Token;
import org.apache.log4j.Logger;
import org.apache.sqoop.common.ImmutableContext;
import org.apache.sqoop.common.MutableContext;
import org.apache.sqoop.connector.hdfs.HdfsConstants;
import org.apache.sqoop.job.etl.TransferableContext;

/**
 * Sqoop is designed in a way to abstract connectors from execution engine. Hence the security portion
 * (like generating and distributing delegation tokens) won't happen automatically for us under the hood
 * and we have to do everything manually.
 */
public class SecurityUtils {

    private static final Logger LOG = Logger.getLogger(SecurityUtils.class);

    /**
     * Creates proxy user for user who submitted the Sqoop job (e.g. who has issued the "start job" commnad)
     */
    static public UserGroupInformation createProxyUser(TransferableContext context) throws IOException {
        return UserGroupInformation.createProxyUser(context.getUser(), UserGroupInformation.getLoginUser());
    }

    /**
     * Creates proxy user and load's it up with all delegation tokens that we have created ourselves
     */
    static public UserGroupInformation createProxyUserAndLoadDelegationTokens(TransferableContext context)
            throws IOException {
        UserGroupInformation proxyUser = createProxyUser(context);
        loadDelegationTokensToUGI(proxyUser, context.getContext());

        return proxyUser;
    }

    /**
     * Generate delegation tokens for current user (this code is suppose to run in doAs) and store them
     * serialized in given mutable context.
     */
    static public void generateDelegationTokens(MutableContext context, Path path, Configuration configuration)
            throws IOException {
        if (!UserGroupInformation.isSecurityEnabled()) {
            LOG.info("Running on unsecured cluster, skipping delegation token generation.");
            return;
        }

        // String representation of all tokens that we will create (most likely single one)
        List<String> tokens = new LinkedList<>();

        Credentials credentials = new Credentials();
        TokenCache.obtainTokensForNamenodes(credentials, new Path[] { path }, configuration);
        for (Token token : credentials.getAllTokens()) {
            LOG.info("Generated token: " + token.toString());
            tokens.add(serializeToken(token));
        }

        // The context classes are transferred via "Credentials" rather then with jobconf, so we're not leaking the DT out here
        if (tokens.size() > 0) {
            context.setString(HdfsConstants.DELEGATION_TOKENS, StringUtils.join(tokens, " "));
        }
    }

    /**
     * Loads delegation tokens that we created and serialize into the mutable context
     */
    static public void loadDelegationTokensToUGI(UserGroupInformation ugi, ImmutableContext context)
            throws IOException {
        String tokenList = context.getString(HdfsConstants.DELEGATION_TOKENS);
        if (tokenList == null) {
            LOG.info("No delegation tokens found");
            return;
        }

        for (String stringToken : tokenList.split(" ")) {
            Token token = deserializeToken(stringToken);
            LOG.info("Loaded delegation token: " + token.toString());
            ugi.addToken(token);
        }
    }

    /**
     * Serialize given token into String.
     *
     * We'll convert token to byte[] using Writable methods fro I/O and then Base64
     * encode the bytes to a human readable string.
     */
    static public String serializeToken(Token token) throws IOException {
        // Serialize the Token to a byte array
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        token.write(dos);
        baos.flush();

        return Base64.encodeBase64String(baos.toByteArray());
    }

    /**
     * Deserialize token from given String.
     *
     * See serializeToken for details how the token is expected to be serialized.
     */
    static public Token deserializeToken(String stringToken) throws IOException {
        Token token = new Token();
        byte[] tokenBytes = Base64.decodeBase64(stringToken);

        ByteArrayInputStream bais = new ByteArrayInputStream(tokenBytes);
        DataInputStream dis = new DataInputStream(bais);
        token.readFields(dis);

        return token;
    }

    private SecurityUtils() {
        // Initialization is prohibited
    }
}