xmpp/sasl.go
author Chris Jones <christian.jones@sri.com>
Sun, 09 Feb 2014 09:50:38 -0700
changeset 182 626c390682fc
parent 153 bbd4166df95d
child 163 3f891f7fe817
permissions -rw-r--r--
Added a license (and my email address).
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     1
// Deal with SASL authentication.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     2
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     3
package xmpp
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     4
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     5
import (
145
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
     6
	"crypto/md5"
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
     7
	"crypto/rand"
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
     8
	"encoding/base64"
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     9
	"encoding/xml"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    10
	"fmt"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    11
	"math/big"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    12
	"regexp"
145
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
    13
	"strings"
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    14
)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    15
150
fa7f6ff10c67 Code reorder and doc cleanup.
Chris Jones <christian.jones@sri.com>
parents: 147
diff changeset
    16
// Server is advertising auth mechanisms it supports. Choose one and
fa7f6ff10c67 Code reorder and doc cleanup.
Chris Jones <christian.jones@sri.com>
parents: 147
diff changeset
    17
// respond.
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    18
// BUG(cjyar): Doesn't implement TLS/SASL EXTERNAL.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    19
func (cl *Client) chooseSasl(fe *Features) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    20
	var digestMd5 bool
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    21
	for _, m := range fe.Mechanisms.Mechanism {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    22
		switch strings.ToLower(m) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    23
		case "digest-md5":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    24
			digestMd5 = true
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    25
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    26
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    27
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    28
	if digestMd5 {
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
    29
		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"},
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
    30
			Mechanism: "DIGEST-MD5"}
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    31
		cl.sendXml <- auth
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    32
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    33
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    34
150
fa7f6ff10c67 Code reorder and doc cleanup.
Chris Jones <christian.jones@sri.com>
parents: 147
diff changeset
    35
// Server is responding to our auth request.
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    36
func (cl *Client) handleSasl(srv *auth) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    37
	switch strings.ToLower(srv.XMLName.Local) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    38
	case "challenge":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    39
		b64 := base64.StdEncoding
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    40
		str, err := b64.DecodeString(srv.Chardata)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    41
		if err != nil {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    42
			Warn.Logf("SASL challenge decode: %s", err)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    43
			return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    44
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    45
		srvMap := parseSasl(string(str))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    46
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    47
		if cl.saslExpected == "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    48
			cl.saslDigest1(srvMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    49
		} else {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    50
			cl.saslDigest2(srvMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    51
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    52
	case "failure":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    53
		Info.Log("SASL authentication failed")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    54
	case "success":
153
bbd4166df95d Simplified the API: There's only one constructor, and it does everything necessary to initiate the stream. StartSession() and Roster.Update() have both been eliminated.
Chris Jones <christian.jones@sri.com>
parents: 150
diff changeset
    55
		cl.setStatus(StatusAuthenticated)
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    56
		Info.Log("Sasl authentication succeeded")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    57
		cl.Features = nil
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    58
		ss := &stream{To: cl.Jid.Domain, Version: XMPPVersion}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    59
		cl.sendXml <- ss
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    60
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    61
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    62
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    63
func (cl *Client) saslDigest1(srvMap map[string]string) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    64
	// Make sure it supports qop=auth
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    65
	var hasAuth bool
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    66
	for _, qop := range strings.Fields(srvMap["qop"]) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    67
		if qop == "auth" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    68
			hasAuth = true
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    69
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    70
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    71
	if !hasAuth {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    72
		Warn.Log("Server doesn't support SASL auth")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    73
		return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    74
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    75
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    76
	// Pick a realm.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    77
	var realm string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    78
	if srvMap["realm"] != "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    79
		realm = strings.Fields(srvMap["realm"])[0]
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    80
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    81
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    82
	passwd := cl.password
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    83
	nonce := srvMap["nonce"]
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    84
	digestUri := "xmpp/" + cl.Jid.Domain
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    85
	nonceCount := int32(1)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    86
	nonceCountStr := fmt.Sprintf("%08x", nonceCount)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    87
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    88
	// Begin building the response. Username is
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    89
	// user@domain or just domain.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    90
	var username string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    91
	if cl.Jid.Node == "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    92
		username = cl.Jid.Domain
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    93
	} else {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    94
		username = cl.Jid.Node
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    95
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    96
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    97
	// Generate our own nonce from random data.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    98
	randSize := big.NewInt(0)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    99
	randSize.Lsh(big.NewInt(1), 64)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   100
	cnonce, err := rand.Int(rand.Reader, randSize)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   101
	if err != nil {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   102
		Warn.Logf("SASL rand: %s", err)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   103
		return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   104
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   105
	cnonceStr := fmt.Sprintf("%016x", cnonce)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   106
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   107
	/* Now encode the actual password response, as well as the
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   108
	 * expected next challenge from the server. */
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   109
	response := saslDigestResponse(username, realm, passwd, nonce,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   110
		cnonceStr, "AUTHENTICATE", digestUri, nonceCountStr)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   111
	next := saslDigestResponse(username, realm, passwd, nonce,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   112
		cnonceStr, "", digestUri, nonceCountStr)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   113
	cl.saslExpected = next
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   114
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   115
	// Build the map which will be encoded.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   116
	clMap := make(map[string]string)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   117
	clMap["realm"] = `"` + realm + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   118
	clMap["username"] = `"` + username + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   119
	clMap["nonce"] = `"` + nonce + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   120
	clMap["cnonce"] = `"` + cnonceStr + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   121
	clMap["nc"] = nonceCountStr
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   122
	clMap["qop"] = "auth"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   123
	clMap["digest-uri"] = `"` + digestUri + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   124
	clMap["response"] = response
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   125
	if srvMap["charset"] == "utf-8" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   126
		clMap["charset"] = "utf-8"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   127
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   128
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   129
	// Encode the map and send it.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   130
	clStr := packSasl(clMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   131
	b64 := base64.StdEncoding
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   132
	clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "response"},
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   133
		Chardata: b64.EncodeToString([]byte(clStr))}
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   134
	cl.sendXml <- clObj
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   135
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   136
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   137
func (cl *Client) saslDigest2(srvMap map[string]string) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   138
	if cl.saslExpected == srvMap["rspauth"] {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   139
		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "response"}}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   140
		cl.sendXml <- clObj
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   141
	} else {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   142
		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "failure"}, Any: &Generic{XMLName: xml.Name{Space: NsSASL,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   143
			Local: "abort"}}}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   144
		cl.sendXml <- clObj
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   145
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   146
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   147
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   148
// Takes a string like `key1=value1,key2="value2"...` and returns a
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   149
// key/value map.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   150
func parseSasl(in string) map[string]string {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   151
	re := regexp.MustCompile(`([^=]+)="?([^",]+)"?,?`)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   152
	strs := re.FindAllStringSubmatch(in, -1)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   153
	m := make(map[string]string)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   154
	for _, pair := range strs {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   155
		key := strings.ToLower(string(pair[1]))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   156
		value := string(pair[2])
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   157
		m[key] = value
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   158
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   159
	return m
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   160
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   161
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   162
// Inverse of parseSasl().
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   163
func packSasl(m map[string]string) string {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   164
	var terms []string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   165
	for key, value := range m {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   166
		if key == "" || value == "" || value == `""` {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   167
			continue
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   168
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   169
		terms = append(terms, key+"="+value)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   170
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   171
	return strings.Join(terms, ",")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   172
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   173
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   174
// Computes the response string for digest authentication.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   175
func saslDigestResponse(username, realm, passwd, nonce, cnonceStr,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   176
	authenticate, digestUri, nonceCountStr string) string {
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   177
	h := func(text string) string {
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   178
		h := md5.New()
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   179
		h.Write([]byte(text))
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   180
		return string(h.Sum(nil))
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   181
	}
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   182
	hex := func(input string) string {
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   183
		return fmt.Sprintf("%x", input)
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   184
	}
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   185
	kd := func(secret, data string) string {
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   186
		return h(secret + ":" + data)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   187
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   188
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   189
	a1 := h(username+":"+realm+":"+passwd) + ":" +
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   190
		nonce + ":" + cnonceStr
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   191
	a2 := authenticate + ":" + digestUri
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   192
	response := hex(kd(hex(h(a1)), nonce+":"+
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   193
		nonceCountStr+":"+cnonceStr+":auth:"+
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   194
		hex(h(a2))))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   195
	return response
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   196
}