@Test public void testCopyFromHostIncompatibleShuffleVersion() throws Exception { String replyHash = SecureShuffleUtils.generateHash(encHash.getBytes(), key); when(connection.getResponseCode()).thenReturn(200); when(connection.getHeaderField(ShuffleHeader.HTTP_HEADER_NAME)) .thenReturn("mapreduce").thenReturn("other").thenReturn("other"); when(connection.getHeaderField(ShuffleHeader.HTTP_HEADER_VERSION)) .thenReturn("1.0.1").thenReturn("1.0.0").thenReturn("1.0.1"); when(connection.getHeaderField( SecureShuffleUtils.HTTP_HEADER_REPLY_URL_HASH)).thenReturn(replyHash); ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]); when(connection.getInputStream()).thenReturn(in); for (int i = 0; i < 3; ++i) { Fetcher<Text,Text> underTest = new FakeFetcher<Text,Text>(job, id, ss, mm, r, metrics, except, key, connection); underTest.copyFromHost(host); } verify(connection, times(3)).addRequestProperty( SecureShuffleUtils.HTTP_HEADER_URL_HASH, encHash); verify(allErrs, times(3)).increment(1); verify(ss, times(3)).copyFailed(map1ID, host, false, false); verify(ss, times(3)).copyFailed(map2ID, host, false, false); verify(ss, times(3)).putBackKnownMapOutput(any(MapHost.class), eq(map1ID)); verify(ss, times(3)).putBackKnownMapOutput(any(MapHost.class), eq(map2ID)); }
.retrieveTokenSecret(jobId); String enc_str = SecureShuffleUtils.buildMsgFrom(request); SecureShuffleUtils.verifyReply(urlHashStr, enc_str, tokenSecret); } catch (IOException ioe) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED); String reply = SecureShuffleUtils.generateHash(urlHashStr.getBytes(), tokenSecret); response.addHeader(SecureShuffleUtils.HTTP_HEADER_REPLY_URL_HASH, reply);
String msgToEncode = SecureShuffleUtils.buildMsgFrom(url); String encHash = SecureShuffleUtils.hashFromString(msgToEncode, jobTokenSecret); SecureShuffleUtils.verifyReply(replyHash, encHash, jobTokenSecret); LOG.info("for url="+msgToEncode+" sent hash and receievd reply"); } catch (IOException ie) {
private void setupConnectionsWithRetry(URL url) throws IOException { openConnectionWithRetry(url); if (stopped) { return; } // generate hash of the url String msgToEncode = SecureShuffleUtils.buildMsgFrom(url); String encHash = SecureShuffleUtils.hashFromString(msgToEncode, shuffleSecretKey); setupShuffleConnection(encHash); connect(connection, connectionTimeout); // verify that the thread wasn't stopped during calls to connect if (stopped) { return; } verifyConnection(url, msgToEncode, encHash); }
/** * Shuffle specific utils - build string for encoding from URL * @param request * @return string for encoding */ public static String buildMsgFrom(HttpServletRequest request ) { return buildMsgFrom(request.getRequestURI(), request.getQueryString(), request.getLocalPort()); } /**
String enc_str = SecureShuffleUtils.buildMsgFrom(url); URLConnection connectionGood = url.openConnection(); String urlHashGood = SecureShuffleUtils.generateHash(enc_str.getBytes(), tokenSecret); // valid hash jtSecretManager); SecretKey badSecret = JobTokenSecretManager.createSecretKey(badToken.getPassword()); String urlHashBad = SecureShuffleUtils.generateHash(enc_str.getBytes(), badSecret); // invalid hash
private void verifyConnection(URL url, String msgToEncode, String encHash) throws IOException { // Validate response code int rc = connection.getResponseCode(); if (rc != HttpURLConnection.HTTP_OK) { throw new IOException( "Got invalid response code " + rc + " from " + url + ": " + connection.getResponseMessage()); } // get the shuffle version if (!ShuffleHeader.DEFAULT_HTTP_HEADER_NAME.equals( connection.getHeaderField(ShuffleHeader.HTTP_HEADER_NAME)) || !ShuffleHeader.DEFAULT_HTTP_HEADER_VERSION.equals( connection.getHeaderField(ShuffleHeader.HTTP_HEADER_VERSION))) { throw new IOException("Incompatible shuffle response version"); } // get the replyHash which is HMac of the encHash we sent to the server String replyHash = connection.getHeaderField(SecureShuffleUtils.HTTP_HEADER_REPLY_URL_HASH); if(replyHash==null) { throw new IOException("security validation of TT Map output failed"); } LOG.debug("url="+msgToEncode+";encHash="+encHash+";replyHash="+replyHash); // verify that replyHash is HMac of encHash SecureShuffleUtils.verifyReply(replyHash, encHash, shuffleSecretKey); LOG.debug("for url="+msgToEncode+" sent hash and received reply"); }
/** * Base64 encoded hash of msg * @param msg */ public static String generateHash(byte[] msg, SecretKey key) { return new String(Base64.encodeBase64(generateByteHash(msg, key)), Charsets.UTF_8); }
public static String createDigest(byte[] password, String data) throws IOException { SecretKey key = JobTokenSecretManager.createSecretKey(password); return SecureShuffleUtils.hashFromString(data, key); }
/** * verify that base64Hash is same as HMacHash(msg) * @param base64Hash (Base64 encoded hash) * @param msg * @throws IOException if not the same */ public static void verifyReply(String base64Hash, String msg, SecretKey key) throws IOException { byte[] hash = Base64.decodeBase64(base64Hash.getBytes(Charsets.UTF_8)); boolean res = verifyHash(hash, msg.getBytes(Charsets.UTF_8), key); if(res != true) { throw new IOException("Verification of the hashReply failed"); } }
String enc_str = SecureShuffleUtils.buildMsgFrom(requestUri); SecureShuffleUtils.verifyReply(urlHashStr, enc_str, tokenSecret); SecureShuffleUtils.generateHash(urlHashStr.getBytes(Charsets.UTF_8), tokenSecret); response.setHeader(SecureShuffleUtils.HTTP_HEADER_REPLY_URL_HASH, reply);
private void setupConnectionsWithRetry(MapHost host, Set<TaskAttemptID> remaining, URL url) throws IOException { openConnectionWithRetry(host, remaining, url); if (stopped) { return; } // generate hash of the url String msgToEncode = SecureShuffleUtils.buildMsgFrom(url); String encHash = SecureShuffleUtils.hashFromString(msgToEncode, shuffleSecretKey); setupShuffleConnection(encHash); connect(connection, connectionTimeout); // verify that the thread wasn't stopped during calls to connect if (stopped) { return; } verifyConnection(url, msgToEncode, encHash); }
/** * Shuffle specific utils - build string for encoding from URL * @param url * @return string for encoding */ public static String buildMsgFrom(URL url) { return buildMsgFrom(url.getPath(), url.getQuery(), url.getPort()); } /**
private void verifyConnection(URL url, String msgToEncode, String encHash) throws IOException { // Validate response code int rc = connection.getResponseCode(); if (rc != HttpURLConnection.HTTP_OK) { throw new IOException( "Got invalid response code " + rc + " from " + url + ": " + connection.getResponseMessage()); } // get the shuffle version if (!ShuffleHeader.DEFAULT_HTTP_HEADER_NAME.equals( connection.getHeaderField(ShuffleHeader.HTTP_HEADER_NAME)) || !ShuffleHeader.DEFAULT_HTTP_HEADER_VERSION.equals( connection.getHeaderField(ShuffleHeader.HTTP_HEADER_VERSION))) { throw new IOException("Incompatible shuffle response version"); } // get the replyHash which is HMac of the encHash we sent to the server String replyHash = connection.getHeaderField(SecureShuffleUtils.HTTP_HEADER_REPLY_URL_HASH); if(replyHash==null) { throw new IOException("security validation of TT Map output failed"); } LOG.debug("url="+msgToEncode+";encHash="+encHash+";replyHash="+replyHash); // verify that replyHash is HMac of encHash SecureShuffleUtils.verifyReply(replyHash, encHash, shuffleSecretKey); LOG.info("for url="+msgToEncode+" sent hash and received reply"); }
/** * Base64 encoded hash of msg * @param msg */ public static String generateHash(byte[] msg, SecretKey key) { return new String(Base64.encodeBase64(generateByteHash(msg, key)), Charsets.UTF_8); }
public static String createDigest(byte[] password, String data) throws IOException { SecretKey key = JobTokenSecretManager.createSecretKey(password); return SecureShuffleUtils.hashFromString(data, key); }
/** * verify that base64Hash is same as HMacHash(msg) * @param base64Hash (Base64 encoded hash) * @param msg * @throws IOException if not the same */ public static void verifyReply(String base64Hash, String msg, SecretKey key) throws IOException { byte[] hash = Base64.decodeBase64(base64Hash.getBytes(Charsets.UTF_8)); boolean res = verifyHash(hash, msg.getBytes(Charsets.UTF_8), key); if(res != true) { throw new IOException("Verification of the hashReply failed"); } }
String enc_str = SecureShuffleUtils.buildMsgFrom(requestUri); SecureShuffleUtils.verifyReply(urlHashStr, enc_str, tokenSecret); SecureShuffleUtils.generateHash(urlHashStr.getBytes(Charsets.UTF_8), tokenSecret); response.setHeader(SecureShuffleUtils.HTTP_HEADER_REPLY_URL_HASH, reply);
@Test public void testCopyFromHostIncompatibleShuffleVersionWithRetry() throws Exception { String replyHash = SecureShuffleUtils.generateHash(encHash.getBytes(), key); when(connection.getResponseCode()).thenReturn(200); when(connection.getHeaderField(ShuffleHeader.HTTP_HEADER_NAME)) .thenReturn("mapreduce").thenReturn("other").thenReturn("other"); when(connection.getHeaderField(ShuffleHeader.HTTP_HEADER_VERSION)) .thenReturn("1.0.1").thenReturn("1.0.0").thenReturn("1.0.1"); when(connection.getHeaderField( SecureShuffleUtils.HTTP_HEADER_REPLY_URL_HASH)).thenReturn(replyHash); ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]); when(connection.getInputStream()).thenReturn(in); for (int i = 0; i < 3; ++i) { Fetcher<Text,Text> underTest = new FakeFetcher<Text,Text>(jobWithRetry, id, ss, mm, r, metrics, except, key, connection); underTest.copyFromHost(host); } verify(connection, times(3)).addRequestProperty( SecureShuffleUtils.HTTP_HEADER_URL_HASH, encHash); verify(allErrs, times(3)).increment(1); verify(ss, times(3)).copyFailed(map1ID, host, false, false); verify(ss, times(3)).copyFailed(map2ID, host, false, false); verify(ss, times(3)).putBackKnownMapOutput(any(MapHost.class), eq(map1ID)); verify(ss, times(3)).putBackKnownMapOutput(any(MapHost.class), eq(map2ID)); }
private void setupConnectionsWithRetry(MapHost host, Set<TaskAttemptID> remaining, URL url) throws IOException { openConnectionWithRetry(host, remaining, url); if (stopped) { return; } // generate hash of the url String msgToEncode = SecureShuffleUtils.buildMsgFrom(url); String encHash = SecureShuffleUtils.hashFromString(msgToEncode, shuffleSecretKey); setupShuffleConnection(encHash); connect(connection, connectionTimeout); // verify that the thread wasn't stopped during calls to connect if (stopped) { return; } verifyConnection(url, msgToEncode, encHash); }