コード例 #1
0
ファイル: handler.go プロジェクト: skriptble/nine
// Authenticate implements the Mechanism interface for PlainMech
func (pm plainMech) Authenticate(data string, props stream.Properties) ([]element.Element, stream.Properties, bool) {
	decoded, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		return []element.Element{element.SASLFailure.MalformedRequest}, props, false
	}

	res := strings.Split(string(decoded), "\000")
	if len(res) != 3 {
		return []element.Element{element.SASLFailure.MalformedRequest}, props, false
	}
	identity, user, password := res[0], res[1], res[2]
	err = pm.auth.Authenticate(identity, user, password)
	// TODO: Handle different types of errors
	if err != nil {
		return []element.Element{element.SASLFailure.NotAuthorized}, props, false
	}
	if identity != "" {
		user = identity
	} else {
		// TODO: Add a way to determine the address of the server for the domain
		// part of the jid (do it better than this.)
		user += "@" + props.Domain
	}

	j := jid.New(user)
	props.Header.To = j.String()
	props.Status = props.Status | stream.Restart | stream.Auth
	return []element.Element{element.SASLSuccess}, props, false
}
コード例 #2
0
ファイル: handler.go プロジェクト: skriptble/nine
func (h Handler) GenerateFeature(props stream.Properties) stream.Properties {
	if props.Status&stream.Bind != 0 || props.Status&stream.Auth == 0 {
		return props
	}

	props.Features = append(props.Features, element.Bind)
	return props
}
コード例 #3
0
ファイル: session.go プロジェクト: skriptble/nine
func (sh SessionHandler) HandleFeature(props stream.Properties) stream.Properties {
	if props.Status&stream.Bind != 0 || props.Status&stream.Auth == 0 {
		return props
	}

	props.Features = append(props.Features, element.Session)
	return props
}
コード例 #4
0
ファイル: handler.go プロジェクト: skriptble/nine
func (h *Handler) GenerateFeature(props stream.Properties) stream.Properties {
	if props.Status&stream.Auth != 0 {
		return props
	}
	mechs := element.SASLMechanisms
	for name := range h.mechs {
		mechs = mechs.AddChild(element.New("mechanism").SetText(name))
	}
	props.Features = append(props.Features, mechs)
	return props
}
コード例 #5
0
ファイル: tcp_test.go プロジェクト: skriptble/nine
func TestStartInitiating(t *testing.T) {
	t.Parallel()

	var want, got []byte
	var props stream.Properties
	var err error

	pipe1, pipe2 := net.Pipe()
	tcpTsp := NewTCP(pipe1, stream.Initiating, nil, false)
	props.Header = stream.Header{}

	// Should get error when starting stream with empty header
	_, err = tcpTsp.Start(props)
	if err != stream.ErrHeaderNotSet {
		t.Error("Should get error when starting stream with empty header.")
		t.Errorf("\nWant:%s\nGot :%s", stream.ErrHeaderNotSet, err)
	}

	// Should write header to underlying connection
	hdr := stream.Header{To: "foo", From: "bar"}
	want = hdr.WriteBytes()
	props.Header = hdr
	got = make([]byte, len(want))
	go func() {
		_, err := pipe2.Read(got)
		if err != nil {
			t.Errorf("Unexpected error while reading from pipe2: %s", err)
		}
	}()
	_, err = tcpTsp.Start(props)
	if err != nil {
		t.Errorf("Unexpected error while starting stream: %s", err)
	}
	if !bytes.Equal(want, got) {
		t.Error("Should write header to underlying connection")
		t.Errorf("\nWant:%s\nGot :%s", want, got)
	}
}
コード例 #6
0
ファイル: handler.go プロジェクト: skriptble/nine
func (h Handler) HandleIQ(iq stanza.IQ, props stream.Properties) ([]stanza.Stanza, stream.Properties) {
	var sts []stanza.Stanza
	// ensure we have a bind request
	req, err := stanza.TransformBindRequest(iq)
	if err != nil {
		// TODO: Should this return an error?
		return sts, props
	}
	if req.Resource == "" {
		// TODO: Create a random resource generator
		req.Resource = genResourceID()
	}

	// Should do some resource validation here.
	// TODO: Need to use proper jids here.
	props.Header.To += "/" + req.Resource

	j := jid.New(props.Header.To)
	res := stanza.NewBindResult(iq, j)
	sts = append(sts, res.TransformStanza())

	props.Status = props.Status | stream.Bind
	return sts, props
}
コード例 #7
0
ファイル: tcp.go プロジェクト: skriptble/nine
// Start starts or restarts the stream.
//
// In recieving mode, the transport will wait to recieve a stream header
// from the initiating entity, then sends its own header and the stream
// features. This transport will add the starttls feature under certain
// conditions.
func (t *TCP) Start(props stream.Properties) (stream.Properties, error) {
	if t.mode == stream.Initiating {
		if props.Header == (stream.Header{}) {
			return props, stream.ErrHeaderNotSet
		}
		b := props.Header.WriteBytes()
		_, err := t.Write(b)
		return props, err
	}

	// We're in recieving mode
	if props.Domain == "" {
		return props, stream.ErrDomainNotSet
	}
	var el element.Element
	var h stream.Header
	var err error

	el, err = t.Next()
	if err != nil {
		return props, err
	}

	h, err = stream.NewHeader(el)
	if err != nil {
		return props, err
	}

	h.ID = genStreamID()

	if h.To != props.Domain {
		h.To, h.From = h.From, props.Domain
		b := h.WriteBytes()
		t.Write(b)
		err = t.WriteElement(element.StreamError.HostUnknown)
		props.Status = stream.Closed
		return props, err
	}

	h.From, h.To = props.Domain, h.From
	if props.To != "" {
		h.To = props.To
	}

	props.Header = h

	b := props.Header.WriteBytes()
	_, err = t.Write(b)
	if err != nil {
		return props, err
	}

	ftrs := element.StreamFeatures
	for _, f := range props.Features {
		ftrs = ftrs.AddChild(f)
	}
	// Stream features
	if t.conf != nil && !t.secure {
		tlsFeature := element.StartTLS
		if t.tlsRequired {
			tlsFeature = tlsFeature.AddChild(element.Required)
		}
		// Overwrite any other features
		ftrs.Child = []element.Token{tlsFeature}
	}
	err = t.WriteElement(ftrs)
	return props, err
}
コード例 #8
0
ファイル: tcp_test.go プロジェクト: skriptble/nine
func TestStartReceiving(t *testing.T) {
	t.Parallel()

	var want, got []byte
	var props, gotProps stream.Properties
	var err, wantErr error

	pipe1, pipe2 := net.Pipe()
	tcpTsp := NewTCP(pipe1, stream.Receiving, &tls.Config{}, true)
	props.Header = stream.Header{}

	// Should return Domain Not Set error if the domain isnot set on the
	// stream properties.
	_, err = tcpTsp.Start(props)
	if err != stream.ErrDomainNotSet {
		t.Error("Should return ErrDomainNotSet error if the domain is no set on the properties.")
		t.Errorf("\nWant:%s\nGot :%s", stream.ErrDomainNotSet, err)
	}

	// Should return error from Next
	props.Domain = "localhost"
	err = pipe2.Close()
	if err != nil {
		t.Errorf("Unexpected error from pipe2.Close: %s", err)
	}
	_, err = tcpTsp.Start(props)
	if err != io.EOF {
		t.Error("Should return error from Next")
		t.Errorf("\nWant:%s\nGot :%s", io.EOF, err)
	}

	// Should return error from NewHeader
	pipe1, pipe2 = net.Pipe()
	tcpTsp = NewTCP(pipe1, stream.Receiving, &tls.Config{}, true)
	go func() {
		_, err := pipe2.Write([]byte("<baz xmlns='foo:bar'/>"))
		if err != nil {
			t.Errorf("Unexpected error while writing to pipe2: %s", err)
		}
	}()
	_, err = tcpTsp.Start(props)
	wantErr = fmt.Errorf("Element is not <stream:stream> it is a <foo:bar:baz>")
	if err.Error() != wantErr.Error() {
		t.Error("Should return error from NewHeader")
		t.Errorf("\nWant:%s\nGot :%s", wantErr, err)
	}

	// Should send HostUnknown if the to field of the header does not match the
	// Domain field on properties
	pipe1, pipe2 = net.Pipe()
	tcpTsp = NewTCP(pipe1, stream.Receiving, &tls.Config{}, true)
	go func() {
		hdr := stream.Header{To: "not-localhost", From: "foo@bar"}
		_, err := pipe2.Write(hdr.WriteBytes())
		if err != nil {
			t.Errorf("Unexpected error while writing to pipe2: %s", err)
		}
		hdr.To, hdr.From = hdr.From, "localhost"
		want = hdr.WriteBytes()
		// We need to add an extra 36 bytes for the id length
		hdrLen := len(want) + 36
		want = append(want, element.StreamError.HostUnknown.WriteBytes()...)
		// We need to add an extra 36 bytes for the id length
		got = make([]byte, len(want)+36)
		_, err = pipe2.Read(got)
		if err != nil {
			t.Errorf("Unexpected error while reading from pipe2: %s", err)
		}
		_, err = pipe2.Read(got[hdrLen:])
		if err != nil {
			t.Errorf("Unexpected error while reading from pipe2: %s", err)
		}
	}()
	gotProps, err = tcpTsp.Start(props)
	if err != nil {
		t.Errorf("Unexpected error from Start: %s", err)
	}
	if gotProps.Status != stream.Closed {
		t.Error("Expected stream to be marked as closed after host unknown error")
	}
	// Need to remove stream ID before comparing
	idx := bytes.Index(got, []byte("id='"))
	if idx == -1 {
		t.Error("Received stream is missing id attribute")
	}
	// We slice the id out of the received stream header.
	got = append(got[:idx+4], got[idx+40:]...)
	if !bytes.Equal(want, got) {
		t.Error("Should send HostUnknown if the to field of the header does not match the domain field on properties.")
		t.Errorf("\nWant:%s\nGot :%s", want, got)
	}

	// Should return error from writing header to the underlying connection
	pipe1, pipe2 = net.Pipe()
	tcpTsp = NewTCP(pipe1, stream.Receiving, &tls.Config{}, true)
	go func() {
		hdr := stream.Header{To: "localhost", From: "foo@bar"}
		_, err := pipe2.Write(hdr.WriteBytes())
		if err != nil {
			t.Errorf("Unexpected error while writing to pipe2: %s", err)
		}
		err = pipe2.Close()
		if err != nil {
			t.Errorf("Unexpected error while closing pipe2: %s", err)
		}
	}()
	gotProps, err = tcpTsp.Start(props)
	if err != io.ErrClosedPipe {
		t.Error("Should return error from writing header to the underlying connection.")
		t.Errorf("\nWant:%s\nGot :%s", io.ErrClosedPipe, err)
	}

	// Should set the To field to the properties To field if it is set
	props.To = "authenticatedFoo@bar"

	// Should overwrite stream features if there is a tls config and the stream
	// is not yet secure
	pipe1, pipe2 = net.Pipe()
	tcpTsp = NewTCP(pipe1, stream.Receiving, &tls.Config{}, true)
	go func() {
		hdr := stream.Header{To: "localhost", From: "foo@bar"}
		_, err := pipe2.Write(hdr.WriteBytes())
		if err != nil {
			t.Errorf("Unexpected error while writing to pipe2: %s", err)
		}
		// Doing two tests at the same time, because they are orthogonal
		hdr.To, hdr.From = "authenticatedFoo@bar", "localhost"
		want = hdr.WriteBytes()
		// We need to add an extra 36 bytes for the id length
		hdrLen := len(want) + 36
		ftrs := element.StreamFeatures.AddChild(
			element.StartTLS.AddChild(
				element.Required),
		)
		want = append(want, ftrs.WriteBytes()...)
		// We need to add an extra 36 bytes for the id length
		got = make([]byte, len(want)+36)
		_, err = pipe2.Read(got)
		if err != nil {
			t.Errorf("Unexpected error while reading from pipe2: %s", err)
		}
		_, err = pipe2.Read(got[hdrLen:])
		if err != nil {
			t.Errorf("Unexpected error while reading from pipe2: %s", err)
		}
	}()
	gotProps, err = tcpTsp.Start(props)
	if err != nil {
		t.Errorf("Unexpected error from Start: %s", err)
	}
	// Need to remove stream ID before comparing
	idx = bytes.Index(got, []byte("id='"))
	if idx == -1 {
		t.Error("Received stream is missing id attribute")
	}
	// We slice the id out of the received stream header.
	got = append(got[:idx+4], got[idx+40:]...)
	if !bytes.Equal(want, got) {
		t.Error("Should overwrite stream features if there is a tls config and the stream is not yet secure.")
		t.Errorf("\nWant:%s\nGot :%s", want, got)
	}

	// Should be able to start stream
	props.Features = append(props.Features, element.Bind)
	pipe1, pipe2 = net.Pipe()
	tcpTsp = NewTCP(pipe1, stream.Receiving, &tls.Config{}, true)
	tcpTsp.(*TCP).secure = true
	go func() {
		hdr := stream.Header{To: "localhost", From: "foo@bar"}
		_, err := pipe2.Write(hdr.WriteBytes())
		if err != nil {
			t.Errorf("Unexpected error while writing to pipe2: %s", err)
		}
		// Doing two tests at the same time, because they are orthogonal
		hdr.To, hdr.From = "authenticatedFoo@bar", "localhost"
		want = hdr.WriteBytes()
		// We need to add an extra 36 bytes for the id length
		hdrLen := len(want) + 36
		ftrs := element.StreamFeatures.AddChild(element.Bind)
		want = append(want, ftrs.WriteBytes()...)
		// We need to add an extra 36 bytes for the id length
		got = make([]byte, len(want)+36)
		_, err = pipe2.Read(got)
		if err != nil {
			t.Errorf("Unexpected error while reading from pipe2: %s", err)
		}
		_, err = pipe2.Read(got[hdrLen:])
		if err != nil {
			t.Errorf("Unexpected error while reading from pipe2: %s", err)
		}
	}()
	gotProps, err = tcpTsp.Start(props)
	if err != nil {
		t.Errorf("Unexpected error from Start: %s", err)
	}
	// Need to remove stream ID before comparing
	idx = bytes.Index(got, []byte("id='"))
	if idx == -1 {
		t.Error("Received stream is missing id attribute")
	}
	// We slice the id out of the received stream header.
	got = append(got[:idx+4], got[idx+40:]...)
	if !bytes.Equal(want, got) {
		t.Error("Should be able to start stream")
		t.Errorf("\nWant:%s\nGot :%s", want, got)
	}
}