1package xmpp 2 3import ( 4 "encoding/xml" 5 6 "github.com/coyim/coyim/xmpp/data" 7 "github.com/coyim/coyim/xmpp/errors" 8 9 . "gopkg.in/check.v1" 10) 11 12type SaslXMPPSuite struct{} 13 14var _ = Suite(&SaslXMPPSuite{}) 15 16func (s *SaslXMPPSuite) Test_authenticate_failsIfPlainIsNotAnOption(c *C) { 17 conn := conn{} 18 19 err := conn.Authenticate("", "") 20 c.Assert(err, Equals, errUnsupportedSASLMechanism) 21} 22 23func (s *SaslXMPPSuite) Test_authenticate_authenticatesWithUsernameAndPassword(c *C) { 24 out := &mockConnIOReaderWriter{} 25 mockIn := &mockConnIOReaderWriter{read: []byte("<sasl:success xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'></sasl:success>")} 26 conn := conn{ 27 rawOut: out, 28 in: xml.NewDecoder(mockIn), 29 features: data.StreamFeatures{ 30 Mechanisms: data.SaslMechanisms{ 31 Mechanism: []string{"FOO", "PLAIN"}, 32 }, 33 }, 34 } 35 36 e := conn.Authenticate("foo", "bar") 37 c.Assert(e, IsNil) 38 c.Assert(string(out.write), Equals, "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AGZvbwBiYXI=</auth>\n") 39} 40 41func (s *SaslXMPPSuite) Test_authenticate_handlesFailure(c *C) { 42 out := &mockConnIOReaderWriter{} 43 mockIn := &mockConnIOReaderWriter{read: []byte("<sasl:failure xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'><foobar></foobar></sasl:failure>")} 44 conn := conn{ 45 rawOut: out, 46 in: xml.NewDecoder(mockIn), 47 features: data.StreamFeatures{ 48 Mechanisms: data.SaslMechanisms{ 49 Mechanism: []string{"FOO", "PLAIN"}, 50 }, 51 }, 52 } 53 54 e := conn.Authenticate("foo", "bar") 55 c.Assert(e.Error(), Equals, "xmpp: authentication failure: foobar") 56} 57 58func (s *SaslXMPPSuite) Test_authenticate_handlesWrongResponses(c *C) { 59 out := &mockConnIOReaderWriter{} 60 mockIn := &mockConnIOReaderWriter{read: []byte("<sasl:something xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'></sasl:something>")} 61 conn := conn{ 62 rawOut: out, 63 in: xml.NewDecoder(mockIn), 64 features: data.StreamFeatures{ 65 Mechanisms: data.SaslMechanisms{ 66 Mechanism: []string{"FOO", "PLAIN"}, 67 }, 68 }, 69 } 70 71 e := conn.Authenticate("foo", "bar") 72 c.Assert(e, Equals, errors.ErrAuthenticationFailed) 73} 74 75func (s *SaslXMPPSuite) Test_digestMD5_authenticatesWithUsernameAndPassword(c *C) { 76 out := &mockConnIOReaderWriter{} 77 mockIn := &mockConnIOReaderWriter{read: []byte( 78 "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cmVhbG09ImNveS5pbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz</challenge>\n" + 79 "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZA==</challenge>\n" + 80 "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>\n", 81 )} 82 83 mockRand := &mockConnIOReaderWriter{read: []byte{ 84 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 85 }} 86 87 conn := conn{ 88 rawOut: out, 89 in: xml.NewDecoder(mockIn), 90 rand: mockRand, 91 features: data.StreamFeatures{ 92 Mechanisms: data.SaslMechanisms{ 93 Mechanism: []string{"DIGEST-MD5"}, 94 }, 95 }, 96 } 97 98 expectedOut := "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'></auth>\n" + 99 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iZm9vIixyZWFsbT0iY295LmltIixub25jZT0iT0E2TUc5dEVRR20yaGgiLG5jPTAwMDAwMDAxLGNub25jZT0iMDEwMjAzMDQwNTA2MDciLGRpZ2VzdC11cmk9InhtcHAvY295LmltIixyZXNwb25zZT00ZGVlODYyNjkxOTZiNmUxNGI5Zjc2OWZhYmQ5OTdiZCxxb3A9YXV0aA==</response>\n" + 100 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'></response>\n" 101 102 e := conn.Authenticate("foo", "bar") 103 c.Assert(e, IsNil) 104 c.Assert(string(out.write), Equals, expectedOut) 105} 106 107func (s *SaslXMPPSuite) Test_digestMD5_serverFailsToVerifyChallenge(c *C) { 108 out := &mockConnIOReaderWriter{} 109 mockIn := &mockConnIOReaderWriter{read: []byte( 110 "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cmVhbG09ImNveS5pbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz</challenge>\n" + 111 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>", 112 )} 113 114 mockRand := &mockConnIOReaderWriter{read: []byte{ 115 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 116 }} 117 118 conn := conn{ 119 rawOut: out, 120 in: xml.NewDecoder(mockIn), 121 rand: mockRand, 122 features: data.StreamFeatures{ 123 Mechanisms: data.SaslMechanisms{ 124 Mechanism: []string{"DIGEST-MD5"}, 125 }, 126 }, 127 } 128 129 expectedOut := "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'></auth>\n" + 130 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iZm9vIixyZWFsbT0iY295LmltIixub25jZT0iT0E2TUc5dEVRR20yaGgiLG5jPTAwMDAwMDAxLGNub25jZT0iMDEwMjAzMDQwNTA2MDciLGRpZ2VzdC11cmk9InhtcHAvY295LmltIixyZXNwb25zZT00ZGVlODYyNjkxOTZiNmUxNGI5Zjc2OWZhYmQ5OTdiZCxxb3A9YXV0aA==</response>\n" 131 132 e := conn.Authenticate("foo", "bar") 133 c.Assert(e.Error(), Equals, "xmpp: unexpected <response> in urn:ietf:params:xml:ns:xmpp-sasl") 134 c.Assert(string(out.write), Equals, expectedOut) 135} 136 137func (s *SaslXMPPSuite) Test_scramSHA1Auth_authenticatesWithUsernameAndPassword(c *C) { 138 out := &mockConnIOReaderWriter{} 139 mockIn := &mockConnIOReaderWriter{read: []byte( 140 "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj03ZjI5MjhmOWRkYTU2ZDNyZmNOSFlKWTFaVnZXVnM3aixzPVFTWENSK1E2c2VrOGJmOTIsaT00MDk2</challenge>\n" + 141 "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1FL1E5T3BnUWhNd1hjWEhtNGU3N3Q4b2lIT0E9</success>\n", 142 )} 143 144 mockRand := &mockConnIOReaderWriter{read: []byte{ 145 0x7f, 0x29, 0x28, 0xf9, 0xdd, 0xa5, 0x6d, 0xb1, 146 0x60, 0x38, 0xd4, 0x6f, 0xf6, 0xa9, 0x31, 0x75, 147 0xac, 0xb, 148 }} 149 150 conn := conn{ 151 rawOut: out, 152 in: xml.NewDecoder(mockIn), 153 rand: mockRand, 154 features: data.StreamFeatures{ 155 Mechanisms: data.SaslMechanisms{ 156 Mechanism: []string{"SCRAM-SHA-1"}, 157 }, 158 }, 159 } 160 161 expectedOut := "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='SCRAM-SHA-1'>biwsbj11c2VyLHI9N2YyOTI4ZjlkZGE1NmQ=</auth>\n" + 162 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>Yz1iaXdzLHI9N2YyOTI4ZjlkZGE1NmQzcmZjTkhZSlkxWlZ2V1ZzN2oscD1KbWYrcWVpSG5jTXRaSjZ3YnJ5ZFdOQ2N4V1E9</response>\n" 163 164 e := conn.Authenticate("user", "pencil") 165 c.Assert(e, IsNil) 166 c.Assert(string(out.write), Equals, expectedOut) 167} 168