示例#1
0
        /// <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>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;
            }
        }