/// <summary>Sends client SASL negotiation for a peer if required.</summary> /// <param name="peer">connection peer</param> /// <param name="encryptionKeyFactory">for creation of an encryption key</param> /// <param name="accessToken">connection block access token</param> /// <param name="datanodeId">ID of destination DataNode</param> /// <returns>new pair of streams, wrapped after SASL negotiation</returns> /// <exception cref="System.IO.IOException">for any error</exception> public virtual Peer PeerSend(Peer peer, DataEncryptionKeyFactory encryptionKeyFactory , Org.Apache.Hadoop.Security.Token.Token <BlockTokenIdentifier> accessToken, DatanodeID datanodeId) { IOStreamPair ios = CheckTrustAndSend(DataTransferSaslUtil.GetPeerAddress(peer), peer .GetOutputStream(), peer.GetInputStream(), encryptionKeyFactory, accessToken, datanodeId ); // TODO: Consider renaming EncryptedPeer to SaslPeer. return(ios != null ? new EncryptedPeer(peer, ios) : peer); }
/// <summary>Sends client SASL negotiation for specialized encrypted handshake.</summary> /// <param name="underlyingOut">connection output stream</param> /// <param name="underlyingIn">connection input stream</param> /// <param name="encryptionKey">for an encrypted SASL handshake</param> /// <returns>new pair of streams, wrapped after SASL negotiation</returns> /// <exception cref="System.IO.IOException">for any error</exception> private IOStreamPair GetEncryptedStreams(OutputStream underlyingOut, InputStream underlyingIn, DataEncryptionKey encryptionKey) { IDictionary <string, string> saslProps = DataTransferSaslUtil.CreateSaslPropertiesForEncryption (encryptionKey.encryptionAlgorithm); Log.Debug("Client using encryption algorithm {}", encryptionKey.encryptionAlgorithm ); string userName = GetUserNameFromEncryptionKey(encryptionKey); char[] password = DataTransferSaslUtil.EncryptionKeyToPassword(encryptionKey.encryptionKey ); CallbackHandler callbackHandler = new SaslDataTransferClient.SaslClientCallbackHandler (userName, password); return(DoSaslHandshake(underlyingOut, underlyingIn, userName, saslProps, callbackHandler )); }
/// <summary>Receives SASL negotiation for specialized encrypted handshake.</summary> /// <param name="peer">connection peer</param> /// <param name="underlyingOut">connection output stream</param> /// <param name="underlyingIn">connection input stream</param> /// <returns>new pair of streams, wrapped after SASL negotiation</returns> /// <exception cref="System.IO.IOException">for any error</exception> private IOStreamPair GetEncryptedStreams(Peer peer, OutputStream underlyingOut, InputStream underlyingIn) { if (peer.HasSecureChannel() || dnConf.GetTrustedChannelResolver().IsTrusted(DataTransferSaslUtil.GetPeerAddress (peer))) { return(new IOStreamPair(underlyingIn, underlyingOut)); } IDictionary <string, string> saslProps = DataTransferSaslUtil.CreateSaslPropertiesForEncryption (dnConf.GetEncryptionAlgorithm()); if (Log.IsDebugEnabled()) { Log.Debug("Server using encryption algorithm " + dnConf.GetEncryptionAlgorithm()); } CallbackHandler callbackHandler = new SaslDataTransferServer.SaslServerCallbackHandler (new _PasswordFunction_172(this)); return(DoSaslHandshake(underlyingOut, underlyingIn, saslProps, callbackHandler)); }
/// <summary>This method actually executes the client-side SASL handshake.</summary> /// <param name="underlyingOut">connection output stream</param> /// <param name="underlyingIn">connection input stream</param> /// <param name="userName">SASL user name</param> /// <param name="saslProps">properties of SASL negotiation</param> /// <param name="callbackHandler">for responding to SASL callbacks</param> /// <returns>new pair of streams, wrapped after SASL negotiation</returns> /// <exception cref="System.IO.IOException">for any error</exception> private IOStreamPair DoSaslHandshake(OutputStream underlyingOut, InputStream underlyingIn , string userName, IDictionary <string, string> saslProps, CallbackHandler callbackHandler ) { DataOutputStream @out = new DataOutputStream(underlyingOut); DataInputStream @in = new DataInputStream(underlyingIn); SaslParticipant sasl = SaslParticipant.CreateClientSaslParticipant(userName, saslProps , callbackHandler); @out.WriteInt(SaslTransferMagicNumber); @out.Flush(); try { // Start of handshake - "initial response" in SASL terminology. DataTransferSaslUtil.SendSaslMessage(@out, new byte[0]); // step 1 byte[] remoteResponse = DataTransferSaslUtil.ReadSaslMessage(@in); byte[] localResponse = sasl.EvaluateChallengeOrResponse(remoteResponse); IList <CipherOption> cipherOptions = null; if (DataTransferSaslUtil.RequestedQopContainsPrivacy(saslProps)) { // Negotiate cipher suites if configured. Currently, the only supported // cipher suite is AES/CTR/NoPadding, but the protocol allows multiple // values for future expansion. string cipherSuites = conf.Get(DFSConfigKeys.DfsEncryptDataTransferCipherSuitesKey ); if (cipherSuites != null && !cipherSuites.IsEmpty()) { if (!cipherSuites.Equals(CipherSuite.AesCtrNopadding.GetName())) { throw new IOException(string.Format("Invalid cipher suite, %s=%s", DFSConfigKeys. DfsEncryptDataTransferCipherSuitesKey, cipherSuites)); } CipherOption option = new CipherOption(CipherSuite.AesCtrNopadding); cipherOptions = Lists.NewArrayListWithCapacity(1); cipherOptions.AddItem(option); } } DataTransferSaslUtil.SendSaslMessageAndNegotiationCipherOptions(@out, localResponse , cipherOptions); // step 2 (client-side only) SaslResponseWithNegotiatedCipherOption response = DataTransferSaslUtil.ReadSaslMessageAndNegotiatedCipherOption (@in); localResponse = sasl.EvaluateChallengeOrResponse(response.payload); System.Diagnostics.Debug.Assert(localResponse == null); // SASL handshake is complete DataTransferSaslUtil.CheckSaslComplete(sasl, saslProps); CipherOption cipherOption = null; if (sasl.IsNegotiatedQopPrivacy()) { // Unwrap the negotiated cipher option cipherOption = DataTransferSaslUtil.Unwrap(response.cipherOption, sasl); } // If negotiated cipher option is not null, we will use it to create // stream pair. return(cipherOption != null?DataTransferSaslUtil.CreateStreamPair(conf, cipherOption , underlyingOut, underlyingIn, false) : sasl.CreateStreamPair(@out, @in)); } catch (IOException ioe) { DataTransferSaslUtil.SendGenericSaslErrorMessage(@out, ioe.Message); throw; } }
/// <summary>Sends a SASL negotiation message indicating an invalid key error.</summary> /// <param name="out">stream to receive message</param> /// <param name="message">to send</param> /// <exception cref="System.IO.IOException">for any error</exception> private static void SendInvalidKeySaslErrorMessage(DataOutputStream @out, string message) { DataTransferSaslUtil.SendSaslMessage(@out, DataTransferProtos.DataTransferEncryptorMessageProto.DataTransferEncryptorStatus .ErrorUnknownKey, null, message); }
/// <summary>This method actually executes the server-side SASL handshake.</summary> /// <param name="underlyingOut">connection output stream</param> /// <param name="underlyingIn">connection input stream</param> /// <param name="saslProps">properties of SASL negotiation</param> /// <param name="callbackHandler">for responding to SASL callbacks</param> /// <returns>new pair of streams, wrapped after SASL negotiation</returns> /// <exception cref="System.IO.IOException">for any error</exception> private IOStreamPair DoSaslHandshake(OutputStream underlyingOut, InputStream underlyingIn , IDictionary <string, string> saslProps, CallbackHandler callbackHandler) { DataInputStream @in = new DataInputStream(underlyingIn); DataOutputStream @out = new DataOutputStream(underlyingOut); SaslParticipant sasl = SaslParticipant.CreateServerSaslParticipant(saslProps, callbackHandler ); int magicNumber = @in.ReadInt(); if (magicNumber != SaslTransferMagicNumber) { throw new InvalidMagicNumberException(magicNumber, dnConf.GetEncryptDataTransfer( )); } try { // step 1 byte[] remoteResponse = DataTransferSaslUtil.ReadSaslMessage(@in); byte[] localResponse = sasl.EvaluateChallengeOrResponse(remoteResponse); DataTransferSaslUtil.SendSaslMessage(@out, localResponse); // step 2 (server-side only) IList <CipherOption> cipherOptions = Lists.NewArrayList(); remoteResponse = DataTransferSaslUtil.ReadSaslMessageAndNegotiationCipherOptions( @in, cipherOptions); localResponse = sasl.EvaluateChallengeOrResponse(remoteResponse); // SASL handshake is complete DataTransferSaslUtil.CheckSaslComplete(sasl, saslProps); CipherOption cipherOption = null; if (sasl.IsNegotiatedQopPrivacy()) { // Negotiate a cipher option cipherOption = DataTransferSaslUtil.NegotiateCipherOption(dnConf.GetConf(), cipherOptions ); if (cipherOption != null) { if (Log.IsDebugEnabled()) { Log.Debug("Server using cipher suite " + cipherOption.GetCipherSuite().GetName()); } } } // If negotiated cipher option is not null, wrap it before sending. DataTransferSaslUtil.SendSaslMessageAndNegotiatedCipherOption(@out, localResponse , DataTransferSaslUtil.Wrap(cipherOption, sasl)); // If negotiated cipher option is not null, we will use it to create // stream pair. return(cipherOption != null?DataTransferSaslUtil.CreateStreamPair(dnConf.GetConf (), cipherOption, underlyingOut, underlyingIn, true) : sasl.CreateStreamPair(@out , @in)); } catch (IOException ioe) { if (ioe is SaslException && ioe.InnerException != null && ioe.InnerException is InvalidEncryptionKeyException) { // This could just be because the client is long-lived and hasn't gotten // a new encryption key from the NN in a while. Upon receiving this // error, the client will get a new encryption key from the NN and retry // connecting to this DN. SendInvalidKeySaslErrorMessage(@out, ioe.InnerException.Message); } else { DataTransferSaslUtil.SendGenericSaslErrorMessage(@out, ioe.Message); } throw; } }
/// <summary>Receives SASL negotiation for general-purpose handshake.</summary> /// <param name="peer">connection peer</param> /// <param name="underlyingOut">connection output stream</param> /// <param name="underlyingIn">connection input stream</param> /// <returns>new pair of streams, wrapped after SASL negotiation</returns> /// <exception cref="System.IO.IOException">for any error</exception> private IOStreamPair GetSaslStreams(Peer peer, OutputStream underlyingOut, InputStream underlyingIn) { if (peer.HasSecureChannel() || dnConf.GetTrustedChannelResolver().IsTrusted(DataTransferSaslUtil.GetPeerAddress (peer))) { return(new IOStreamPair(underlyingIn, underlyingOut)); } SaslPropertiesResolver saslPropsResolver = dnConf.GetSaslPropsResolver(); IDictionary <string, string> saslProps = saslPropsResolver.GetServerProperties(DataTransferSaslUtil.GetPeerAddress (peer)); CallbackHandler callbackHandler = new SaslDataTransferServer.SaslServerCallbackHandler (new _PasswordFunction_292(this)); return(DoSaslHandshake(underlyingOut, underlyingIn, saslProps, callbackHandler)); }
/// <exception cref="System.IO.IOException"/> public char[] Apply(string userName) { return(DataTransferSaslUtil.EncryptionKeyToPassword(this._enclosing.GetEncryptionKeyFromUserName (userName))); }