vines-backdoor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +81 -0
- data/Rakefile +3 -0
- data/lib/vines/backdoor.rb +8 -0
- data/lib/vines/backdoor/auth.rb +39 -0
- data/lib/vines/backdoor/bind.rb +35 -0
- data/lib/vines/backdoor/config/port.rb +14 -0
- data/lib/vines/backdoor/gap.rb +44 -0
- data/lib/vines/backdoor/stream/http.rb +35 -0
- data/lib/vines/backdoor/stream/http/start.rb +24 -0
- data/lib/vines/backdoor/version.rb +6 -0
- data/spec/lib/vines/backdoor/auth_spec.rb +67 -0
- data/spec/lib/vines/backdoor/bind_spec.rb +73 -0
- data/spec/lib/vines/backdoor/gap_spec.rb +71 -0
- data/spec/lib/vines/backdoor/stream/http/start_spec.rb +31 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/helpers.rb +14 -0
- data/vines-backdoor.gemspec +28 -0
- metadata +153 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Strech (Sergey Fedorov)
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/Strech/vines-backdoor.png?branch=master)](https://travis-ci.org/Strech/vines-backdoor)
|
2
|
+
[![Code Climate](https://codeclimate.com/github/Strech/vines-backdoor.png)](https://codeclimate.com/github/Strech/vines-backdoor)
|
3
|
+
|
4
|
+
# Vines::Backdoor
|
5
|
+
|
6
|
+
Allows you to authenticate and generate bosh session for vines user by sigle request without password.
|
7
|
+
|
8
|
+
All that you need – a secret key from backdoor of your vines
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'vines-backdoor'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install vines-backdoor
|
23
|
+
|
24
|
+
## :warning: Attention :warning:
|
25
|
+
|
26
|
+
Never, ever, ever use this for external client authentication. This extension is only for internal server use :fire:
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
Modify your vines config file
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
# conf/config.rb
|
34
|
+
|
35
|
+
require 'vines/backdoor'
|
36
|
+
|
37
|
+
# http bind section
|
38
|
+
http '0.0.0.0', 5280 do
|
39
|
+
bind '/http-bind'
|
40
|
+
max_stanza_size 65536
|
41
|
+
max_resources_per_account 5
|
42
|
+
root 'web'
|
43
|
+
vroute ''
|
44
|
+
backdoor 'my-secret-backdoor-key'
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Now http service accept extended requests with some extra data in it.
|
49
|
+
All response messages (errors and success responses) are RFC compatible
|
50
|
+
|
51
|
+
Send authentication and binding request in a batch
|
52
|
+
|
53
|
+
```html
|
54
|
+
<body xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" xmpp:version="1.0"
|
55
|
+
content="text/xml; charset=utf-8" rid="235205804" to="localhost" secure="true" wait="60" hold="1"
|
56
|
+
backdoor="my-secret-backdoor-key">
|
57
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="INTERNAL">user@localhost</auth>
|
58
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
59
|
+
<resource>pidgin</resource>
|
60
|
+
</bind>
|
61
|
+
</body>
|
62
|
+
```
|
63
|
+
|
64
|
+
And get a successful response
|
65
|
+
|
66
|
+
```html
|
67
|
+
<iq type="result" id="235205804">
|
68
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
69
|
+
<jid>user@localhost/pidgin</jid>
|
70
|
+
<sid>f27c71df-f124-4829-b415-5855b8c04109</sid>
|
71
|
+
</bind>
|
72
|
+
</iq>
|
73
|
+
```
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
1. Fork it ( http://github.com/Strech/vines-backdoor/fork )
|
78
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
79
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
80
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
81
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "vines/backdoor/version"
|
3
|
+
require "vines/backdoor/gap"
|
4
|
+
require "vines/backdoor/bind"
|
5
|
+
require "vines/backdoor/auth"
|
6
|
+
require "vines/backdoor/config/port"
|
7
|
+
require "vines/backdoor/stream/http"
|
8
|
+
require "vines/backdoor/stream/http/start"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
module Vines
|
3
|
+
module Backdoor
|
4
|
+
class Auth < Vines::Stream::Client::Auth
|
5
|
+
INTERNAL = "INTERNAL".freeze
|
6
|
+
|
7
|
+
def auth(node)
|
8
|
+
raise StreamErrors::NotAuthorized unless auth?(node)
|
9
|
+
|
10
|
+
node = node.xpath('ns:auth', 'ns' => NS).first
|
11
|
+
|
12
|
+
if node.text.empty?
|
13
|
+
send_auth_fail(SaslErrors::MalformedRequest.new)
|
14
|
+
elsif stream.authentication_mechanisms.include?(node[MECHANISM])
|
15
|
+
if node[MECHANISM] == INTERNAL
|
16
|
+
stream.user = authenticate(node.text) or raise StreamErrors::NotAuthorized
|
17
|
+
end
|
18
|
+
else
|
19
|
+
send_auth_fail(SaslErrors::InvalidMechanism.new)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def auth?(node)
|
25
|
+
node.xpath('ns:auth', 'ns' => NS).any?
|
26
|
+
end
|
27
|
+
|
28
|
+
def authenticate(jid)
|
29
|
+
log.info("Authenticating user: %s" % jid)
|
30
|
+
stream.storage.find_user(jid).tap do |user|
|
31
|
+
log.info("Authentication succeeded (backdoor): %s" % user.jid) if user
|
32
|
+
end
|
33
|
+
rescue => e
|
34
|
+
log.error("Failed to authenticate: #{e.to_s}")
|
35
|
+
raise Vines::SaslErrors::TemporaryAuthFailure
|
36
|
+
end
|
37
|
+
end # class Auth
|
38
|
+
end # module Backdoor
|
39
|
+
end # module Vines
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
module Vines
|
3
|
+
module Backdoor
|
4
|
+
class Bind < Vines::Stream::Client::Bind
|
5
|
+
def bind(node)
|
6
|
+
@attempts += 1
|
7
|
+
raise StreamErrors::NotAuthorized unless bind?(node)
|
8
|
+
raise StreamErrors::PolicyViolation.new('max bind attempts reached') if @attempts > MAX_ATTEMPTS
|
9
|
+
raise StanzaErrors::ResourceConstraint.new(fabricate_request(node), 'wait') if resource_limit_reached?
|
10
|
+
|
11
|
+
stream.bind!(resource(node))
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def bind?(node)
|
16
|
+
node.xpath('ns:bind', 'ns' => NS).any?
|
17
|
+
end
|
18
|
+
|
19
|
+
def resource(node)
|
20
|
+
el = node.xpath('ns:bind/ns:resource', 'ns' => NS).first
|
21
|
+
resource = el ? el.text.strip : ''
|
22
|
+
generate = resource.empty? || !resource_valid?(resource) || resource_used?(resource)
|
23
|
+
generate ? Vines::Kit.uuid : resource
|
24
|
+
end
|
25
|
+
|
26
|
+
def fabricate_request(node)
|
27
|
+
doc = Document.new
|
28
|
+
doc.create_element('iq') do |el|
|
29
|
+
el['id'] = node['rid']
|
30
|
+
el << node.xpath('ns:bind/ns:resource', 'ns' => NS).first
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end # class Bind
|
34
|
+
end # module Backdoor
|
35
|
+
end # module Vines
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Vines
|
3
|
+
class Config
|
4
|
+
class HttpPort
|
5
|
+
def backdoor(secret_key = nil)
|
6
|
+
if secret_key
|
7
|
+
@settings[:backdoor_secret_key] = secret_key
|
8
|
+
else
|
9
|
+
@settings[:backdoor_secret_key]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end # class HttpPort
|
13
|
+
end # class Config
|
14
|
+
end # module Vines
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "nokogiri"
|
3
|
+
|
4
|
+
module Vines
|
5
|
+
module Backdoor
|
6
|
+
class Gap
|
7
|
+
BACKDOOR = "backdoor".freeze
|
8
|
+
|
9
|
+
attr_reader :stream
|
10
|
+
|
11
|
+
def initialize(stream)
|
12
|
+
@stream = stream
|
13
|
+
end
|
14
|
+
|
15
|
+
def node(node)
|
16
|
+
raise StreamErrors::NotAuthorized unless backdoor?(node)
|
17
|
+
|
18
|
+
stream.start_session(node)
|
19
|
+
Backdoor::Auth.new(stream).auth(node)
|
20
|
+
Backdoor::Bind.new(stream).bind(node)
|
21
|
+
|
22
|
+
advance(node)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def advance(node)
|
27
|
+
doc = Nokogiri::XML::Document.new
|
28
|
+
result = doc.create_element('iq', 'id' => node['rid'], 'type' => 'result') do |el|
|
29
|
+
el << doc.create_element('bind') do |bind|
|
30
|
+
bind.default_namespace = Vines::Stream::Client::Bind::NS
|
31
|
+
bind << doc.create_element('jid', stream.user.jid.to_s)
|
32
|
+
bind << doc.create_element('sid', stream.id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
stream.write(result)
|
37
|
+
end
|
38
|
+
|
39
|
+
def backdoor?(node)
|
40
|
+
node[BACKDOOR] && node[BACKDOOR] == @stream.backdoor
|
41
|
+
end
|
42
|
+
end # class Gap
|
43
|
+
end # module Backdoor
|
44
|
+
end # module Vines
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Vines
|
3
|
+
class Stream
|
4
|
+
class Http < Client
|
5
|
+
MECHANISMS = %w[PLAIN INTERNAL].freeze
|
6
|
+
|
7
|
+
def backdoor(*args)
|
8
|
+
config[:http].backdoor(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def authentication_mechanisms
|
12
|
+
MECHANISMS
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_session(node)
|
16
|
+
domain, type, hold, wait, rid = %w[to content hold wait rid].map {|a| (node[a] || '').strip }
|
17
|
+
version = node.attribute_with_ns('version', NAMESPACES[:bosh]).value rescue nil
|
18
|
+
|
19
|
+
@session.inactivity = 20
|
20
|
+
@session.domain = domain
|
21
|
+
@session.content_type = type unless type.empty?
|
22
|
+
@session.hold = hold.to_i unless hold.empty?
|
23
|
+
@session.wait = wait.to_i unless wait.empty?
|
24
|
+
|
25
|
+
raise StreamErrors::UndefinedCondition.new('rid required') if rid.empty?
|
26
|
+
raise StreamErrors::UnsupportedVersion unless version == '1.0'
|
27
|
+
raise StreamErrors::ImproperAddressing unless valid_address?(domain)
|
28
|
+
raise StreamErrors::HostUnknown unless config.vhost?(domain)
|
29
|
+
raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns'] == NAMESPACES[:http_bind]
|
30
|
+
|
31
|
+
Sessions[@session.id] = @session
|
32
|
+
end
|
33
|
+
end # class Http
|
34
|
+
end # class Stream
|
35
|
+
end # module Vines
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
module Vines
|
3
|
+
class Stream
|
4
|
+
class Http
|
5
|
+
class Start < State
|
6
|
+
def node(node)
|
7
|
+
raise StreamErrors::NotAuthorized unless body?(node)
|
8
|
+
if session = Sessions[node['sid']]
|
9
|
+
session.resume(stream, node)
|
10
|
+
else
|
11
|
+
|
12
|
+
if node['backdoor']
|
13
|
+
backdoor = Vines::Backdoor::Gap.new(stream)
|
14
|
+
backdoor.node(node)
|
15
|
+
else
|
16
|
+
stream.start(node)
|
17
|
+
advance
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end # class Start
|
22
|
+
end # class Http
|
23
|
+
end # class Stream
|
24
|
+
end # module Vines
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Vines::Backdoor::Auth do
|
5
|
+
let(:klass) { described_class.new(stream) }
|
6
|
+
let(:storage) { double("Storage") }
|
7
|
+
let(:stream) do
|
8
|
+
double("Stream", storage: storage,
|
9
|
+
authentication_mechanisms: ["INTERNAL"]).as_null_object
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when missing auth namespace" do
|
13
|
+
let(:xml) { node(%q{<body><auth mechanism="INTERNAL">user@localhost</auth></body>}) }
|
14
|
+
|
15
|
+
it { expect { klass.auth(xml) }.to raise_error Vines::StreamErrors::NotAuthorized }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when used unknown mechanism" do
|
19
|
+
let(:xml) do
|
20
|
+
node(%q{<body>
|
21
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="FOO">user@localhost</auth>
|
22
|
+
</body>})
|
23
|
+
end
|
24
|
+
|
25
|
+
after { klass.auth(xml) }
|
26
|
+
|
27
|
+
it { expect(stream).to receive(:error).with(kind_of Vines::SaslErrors::InvalidMechanism) }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when no username is given" do
|
31
|
+
let(:xml) do
|
32
|
+
node(%q{<body>
|
33
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="INTERNAL"></auth>
|
34
|
+
</body>})
|
35
|
+
end
|
36
|
+
|
37
|
+
after { klass.auth(xml) }
|
38
|
+
|
39
|
+
it { expect(stream).to receive(:error).with(kind_of Vines::SaslErrors::MalformedRequest) }
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when user not found" do
|
43
|
+
let(:xml) do
|
44
|
+
node(%q{<body>
|
45
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="INTERNAL">user@localhost</auth>
|
46
|
+
</body>})
|
47
|
+
end
|
48
|
+
|
49
|
+
before { storage.stub(:find_user).with("user@localhost").and_return nil }
|
50
|
+
|
51
|
+
it { expect { klass.auth(xml) }.to raise_error Vines::StreamErrors::NotAuthorized }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when user is authenticated" do
|
55
|
+
let(:user) { double("User", jid: "user@localhost") }
|
56
|
+
let(:xml) do
|
57
|
+
node(%q{<body>
|
58
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="INTERNAL">user@localhost</auth>
|
59
|
+
</body>})
|
60
|
+
end
|
61
|
+
|
62
|
+
before { storage.stub(:find_user).with("user@localhost").and_return user }
|
63
|
+
after { klass.auth(xml) }
|
64
|
+
|
65
|
+
it { expect(stream).to receive(:user=).with(user) }
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Vines::Backdoor::Bind do
|
5
|
+
let(:klass) { described_class.new(stream) }
|
6
|
+
let(:storage) { double("Storage") }
|
7
|
+
let(:stream) { double("Stream", storage: storage) }
|
8
|
+
|
9
|
+
context "when missing bind namespace" do
|
10
|
+
let(:xml) { node(%q{<body><bind><resource>pidgin</resource></bind></body>}) }
|
11
|
+
|
12
|
+
it { expect { klass.bind(xml) }.to raise_error Vines::StreamErrors::NotAuthorized }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when max attemps is reached" do
|
16
|
+
let(:xml) do
|
17
|
+
node(%q{<body>
|
18
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
19
|
+
<resource>pidgin</resource>
|
20
|
+
</bind></body>})
|
21
|
+
end
|
22
|
+
|
23
|
+
before { stub_const("Vines::Stream::Client::Bind::MAX_ATTEMPTS", 0) }
|
24
|
+
|
25
|
+
it { expect { klass.bind(xml) }.to raise_error Vines::StreamErrors::PolicyViolation }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when resource limit is reached" do
|
29
|
+
let(:xml) do
|
30
|
+
node(%q{<body>
|
31
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
32
|
+
<resource>pidgin</resource>
|
33
|
+
</bind></body>})
|
34
|
+
end
|
35
|
+
|
36
|
+
before { klass.stub(resource_limit_reached?: true) }
|
37
|
+
|
38
|
+
it { expect { klass.bind(xml) }.to raise_error Vines::StanzaErrors::ResourceConstraint }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when bind session with given resource" do
|
42
|
+
let(:xml) do
|
43
|
+
node(%q{<body>
|
44
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
45
|
+
<resource>pidgin</resource>
|
46
|
+
</bind></body>})
|
47
|
+
end
|
48
|
+
|
49
|
+
before do
|
50
|
+
klass.stub(resource_valid?: true)
|
51
|
+
klass.stub(resource_limit_reached?: false)
|
52
|
+
klass.stub(:resource_used?).with("pidgin").and_return false
|
53
|
+
end
|
54
|
+
after { klass.bind(xml) }
|
55
|
+
|
56
|
+
it { expect(stream).to receive(:bind!).with("pidgin") }
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when bind session with generated resource" do
|
60
|
+
let(:xml) { node(%q{<body><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></body>}) }
|
61
|
+
|
62
|
+
before do
|
63
|
+
klass.stub(resource_valid?: true)
|
64
|
+
klass.stub(resource_limit_reached?: false)
|
65
|
+
end
|
66
|
+
after { klass.bind(xml) }
|
67
|
+
|
68
|
+
it do
|
69
|
+
expect(Vines::Kit).to receive(:uuid).and_return "random-resource"
|
70
|
+
expect(stream).to receive(:bind!).with("random-resource")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Vines::Backdoor::Gap do
|
5
|
+
let(:klass) { described_class.new(stream) }
|
6
|
+
let(:storage) { double("Storage") }
|
7
|
+
let(:stream) { double("Stream", storage: storage).as_null_object }
|
8
|
+
|
9
|
+
context "when backdoor attribute is missing" do
|
10
|
+
let(:xml) do
|
11
|
+
node(%q{<body>
|
12
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="INTERNAL">user@localhost</auth>
|
13
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
14
|
+
<resource>pidgin</resource>
|
15
|
+
</bind></body>})
|
16
|
+
end
|
17
|
+
|
18
|
+
it { expect { klass.node(xml) }.to raise_error Vines::StreamErrors::NotAuthorized }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when backdoor attribute is wrong" do
|
22
|
+
let(:xml) do
|
23
|
+
node(%q{<body backdoor="12345">
|
24
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="INTERNAL">user@localhost</auth>
|
25
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
26
|
+
<resource>pidgin</resource>
|
27
|
+
</bind></body>})
|
28
|
+
end
|
29
|
+
|
30
|
+
before { stream.stub(backdoor: 9000) }
|
31
|
+
|
32
|
+
it { expect { klass.node(xml) }.to raise_error Vines::StreamErrors::NotAuthorized }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when user is authenticated and session is binded" do
|
36
|
+
let(:user) { double("User", jid: "user@localhost/pidgin") }
|
37
|
+
let(:xml) do
|
38
|
+
node(%q{<body rid="100500" backdoor="9000">
|
39
|
+
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="INTERNAL">user@localhost</auth>
|
40
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
41
|
+
<resource>pidgin</resource>
|
42
|
+
</bind></body>})
|
43
|
+
end
|
44
|
+
let(:expected) do
|
45
|
+
node(%q{<iq id="100500" type="result">
|
46
|
+
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
|
47
|
+
<jid>user@localhost/pidgin</jid>
|
48
|
+
<sid>abcde-12345-fghijk-6789-xyz</sid>
|
49
|
+
</bind></iq>})
|
50
|
+
end
|
51
|
+
|
52
|
+
before do
|
53
|
+
stream.stub(backdoor: "9000")
|
54
|
+
stream.stub(authentication_mechanisms: ["INTERNAL"])
|
55
|
+
stream.stub(user: user)
|
56
|
+
stream.stub(id: "abcde-12345-fghijk-6789-xyz")
|
57
|
+
|
58
|
+
storage.stub(:find_user).with("user@localhost").and_return user
|
59
|
+
|
60
|
+
Vines::Backdoor::Bind.any_instance.stub(resource_valid?: true)
|
61
|
+
Vines::Backdoor::Bind.any_instance.stub(resource_limit_reached?: false)
|
62
|
+
end
|
63
|
+
after { klass.node(xml) }
|
64
|
+
|
65
|
+
it do
|
66
|
+
expect(stream).to receive(:write) do |response|
|
67
|
+
expect(response.to_s).to eq expected.to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Vines::Stream::Http::Start do
|
5
|
+
context "when backdoor attribute present" do
|
6
|
+
let(:start) { described_class.new(stream) }
|
7
|
+
let(:xml) { node(%q{<body xmlns="http://jabber.org/protocol/httpbind" rid="42" backdoor="12345"/>}) }
|
8
|
+
let(:gap) { double("Backdoor gap").as_null_object }
|
9
|
+
let(:stream) { double("Stream", backdoor: "12345") }
|
10
|
+
|
11
|
+
after { em { start.node(xml) } }
|
12
|
+
|
13
|
+
it do
|
14
|
+
expect(Vines::Backdoor::Gap).to receive(:new).with(stream).and_return gap
|
15
|
+
expect(gap).to receive(:node).with(xml)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when backdoor attribute is missing" do
|
20
|
+
let(:start) { described_class.new(stream) }
|
21
|
+
let(:xml) { node(%q{<body xmlns="http://jabber.org/protocol/httpbind" rid="42" />}) }
|
22
|
+
let(:stream) { double("Stream", backdoor: "12345") }
|
23
|
+
|
24
|
+
after { em { start.node(xml) } }
|
25
|
+
|
26
|
+
it do
|
27
|
+
expect(stream).to receive(:start).with(xml)
|
28
|
+
expect(stream).to receive(:advance)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
if ENV["COV"]
|
3
|
+
require "simplecov"
|
4
|
+
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter "/spec/"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require "vines"
|
11
|
+
require "vines/backdoor"
|
12
|
+
|
13
|
+
# Disable vines logger
|
14
|
+
Class.new.extend(Vines::Log).log.level = Logger::FATAL
|
15
|
+
Dir[File.join(File.dirname(__FILE__), 'support', '**', '*.rb')].each { |file| require file }
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.formatter = :progress
|
19
|
+
config.order = :random
|
20
|
+
config.color = true
|
21
|
+
|
22
|
+
include Helpers
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "vines/backdoor/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "vines-backdoor"
|
9
|
+
spec.version = Vines::Backdoor::VERSION
|
10
|
+
spec.authors = ["Strech (Sergey Fedorov)"]
|
11
|
+
spec.email = ["strech_ftf@mail.ru"]
|
12
|
+
spec.summary = "Accelerated http-bind session creation"
|
13
|
+
spec.description = "XMPP protocol extension for Vines server"
|
14
|
+
spec.homepage = "https://github.com/Strech/vines-backdoor"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "vines", ">= 0.4.5"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
25
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
26
|
+
spec.add_development_dependency "simplecov"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vines-backdoor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Strech (Sergey Fedorov)
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-02-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: vines
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.4.5
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ! '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.4.5
|
28
|
+
type: :runtime
|
29
|
+
prerelease: false
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.5'
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.5'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
version_requirements: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.14'
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.14'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: simplecov
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
description: XMPP protocol extension for Vines server
|
95
|
+
email:
|
96
|
+
- strech_ftf@mail.ru
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- .travis.yml
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- lib/vines/backdoor.rb
|
108
|
+
- lib/vines/backdoor/auth.rb
|
109
|
+
- lib/vines/backdoor/bind.rb
|
110
|
+
- lib/vines/backdoor/config/port.rb
|
111
|
+
- lib/vines/backdoor/gap.rb
|
112
|
+
- lib/vines/backdoor/stream/http.rb
|
113
|
+
- lib/vines/backdoor/stream/http/start.rb
|
114
|
+
- lib/vines/backdoor/version.rb
|
115
|
+
- spec/lib/vines/backdoor/auth_spec.rb
|
116
|
+
- spec/lib/vines/backdoor/bind_spec.rb
|
117
|
+
- spec/lib/vines/backdoor/gap_spec.rb
|
118
|
+
- spec/lib/vines/backdoor/stream/http/start_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
- spec/support/helpers.rb
|
121
|
+
- vines-backdoor.gemspec
|
122
|
+
homepage: https://github.com/Strech/vines-backdoor
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 1.8.25
|
144
|
+
signing_key:
|
145
|
+
specification_version: 3
|
146
|
+
summary: Accelerated http-bind session creation
|
147
|
+
test_files:
|
148
|
+
- spec/lib/vines/backdoor/auth_spec.rb
|
149
|
+
- spec/lib/vines/backdoor/bind_spec.rb
|
150
|
+
- spec/lib/vines/backdoor/gap_spec.rb
|
151
|
+
- spec/lib/vines/backdoor/stream/http/start_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
- spec/support/helpers.rb
|