colinmarc / hdfs

A native go client for HDFS
MIT License
1.37k stars 341 forks source link

SASL connections to HDP3 aren't working #218

Closed Viguro79 closed 4 years ago

Viguro79 commented 4 years ago

When I try to use gohdfs on HDP3.1, it won't work. hdfs dfs -ls /data works. But gohdfs ls /data returns an error : Couldn't connect to namenode: no available namenodes: SASL handshake: unexpected QOP in challenge Cluster kerberized + H.A. It's working on HDP2.6 with the same configuration. Is this a known issue?

colinmarc commented 4 years ago

Yeah, I encountered this when trying to test with HDP3 in CI. Unfortunately, I don't have a Kerberized HDP cluster available to test with. I'd welcome contributions here from someone who has the env available to debug.

jlisickigog commented 4 years ago

Hi

We encountered the same problem and after short debug found that the QoP in token can be a list of levels ordered by the preference. For ex. auth-conf,auth. Currently the code assumes that token has only one QoP level. I'm pasting the patch below. The code simply selects the most secure level, thus ignoring the other side's preferences. I don't know the library, so i'm not sure that all the places where the Qop list can be spotted, are covered by this patch.

diff -u -r internal/rpc/kerberos.go internal-new/rpc/kerberos.go
--- internal/rpc/kerberos.go    2020-07-28 17:15:33.000000000 +0200
+++ internal-new/rpc/kerberos.go    2020-07-28 17:14:35.000000000 +0200
@@ -63,7 +63,8 @@
            return err
        }

-       switch challenge.Qop {
+       qopLevel := sasl.HighestQopLevel(challenge.Qop)
+       switch qopLevel {
        case sasl.QopPrivacy, sasl.QopIntegrity:
            // Switch to SASL RPC handler
            c.transport = &saslTransport{
@@ -71,7 +72,7 @@
                    clientID: c.ClientID,
                },
                sessionKey: sessionKey,
-               privacy:    challenge.Qop == sasl.QopPrivacy,
+               privacy:    qopLevel == sasl.QopPrivacy,
            }
        case sasl.QopAuthentication:
            // No special transport is required.
diff -u -r internal/sasl/challenge.go internal-new/sasl/challenge.go
--- internal/sasl/challenge.go  2020-07-28 17:15:33.000000000 +0200
+++ internal-new/sasl/challenge.go  2020-07-28 17:14:35.000000000 +0200
@@ -30,6 +30,21 @@
    Algorithm string
 }

+// HighestQopLevel extracts most secure Qop level from the list provided as an argument.
+func HighestQopLevel(qopListStr string) string {
+   // The qopList is a comma-separated list of qop values, the order of which specifies the preference order.
+   qopList := strings.Split(qopListStr, ",")
+   // Search provided list for most secure qop level.
+   for _, r := range []string{QopPrivacy, QopIntegrity, QopAuthentication} {
+       for _, qop := range qopList {
+           if qop == r {
+               return r
+           }
+       }
+   }
+   return qopListStr
+}
+
 func ParseChallenge(challenge []byte) (*Challenge, error) {
    ch := Challenge{}
colinmarc commented 4 years ago

I can't manage to test on HDP3 - probably because of the cloudera acquisition, the packages aren't easily installable anymore. But I pushed your fix in 9a6156e161288c956ce1d890cda9e6c97c67d065. Hopefully it helps!