Class: Jabber::Bosh::Authentication::SASL

Inherits:
Object
  • Object
show all
Defined in:
lib/jabber4r/bosh/authentication/sasl.rb

Overview

This class provides SASL authentication for BOSH session

Defined Under Namespace

Classes: Query

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(session) ⇒ SASL

Returns a new instance of SASL.



16
17
18
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 16

def initialize(session)
  @session = session
end

Instance Attribute Details

#mechanismsObject (readonly)

Returns the value of attribute mechanisms.



14
15
16
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 14

def mechanisms
  @mechanisms
end

#sessionObject (readonly)

Returns the value of attribute session.



13
14
15
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 13

def session
  @session
end

Instance Method Details

#authenticate(jid, password) ⇒ Object

TODO : Make state machine



142
143
144
145
146
147
148
149
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 142

def authenticate(jid, password)
  open_stream

  return false if pass_authentication(password) == false
  return false if restart_stream == false

  bind_resource
end

#bind_resourceObject



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 106

def bind_resource
  bind = Ox::Element.new("bind").tap do |element|
    element[:xmlns] = "urn:ietf:params:xml:ns:xmpp-bind"

    element << (Ox::Element.new("resource") << session.jid.resource)
  end

  iq = Ox::Element.new("iq").tap do |element|
    element[:id]    = Jabber.gen_random_id
    element[:type]  = "set"
    element[:xmlns] = "jabber:client"

    element << bind
  end

  body = Ox::Element.new("body").tap do |element|
    element[:xmlns]         = 'http://jabber.org/protocol/httpbind'
    element["xmlns:xmpp"]   = "urn:xmpp:xbosh"
    element["xmpp:version"] = "1.0"
    element[:content]       = "text/xml; charset=utf-8"
    element[:rid]           = session.generate_next_rid
    element[:sid]           = session.sid

    element << iq
  end

  response = session.post(Ox.dump body)
  xml = Ox.parse(response.body.tr("'", '"'))

  raise Jabber::XMLMalformedError, "Couldn't find xml tag <iq/>" if xml.locate("iq").empty?
  return false unless xml.iq[:type] == "result"

  true
end

#define_stream_mechanisms(xml) ⇒ Object

Public: …

xml - Ox::Element

Returns Array



156
157
158
159
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 156

def define_stream_mechanisms(xml)
  @mechanisms = xml.locate("stream:features/mechanisms/mechanism/*")
                   .map(&:downcase).map(&:to_sym)
end

#open_streamObject

Internal: Send open stream command to jabber server

Raises XMLMalformedError Returns boolean



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 24

def open_stream
  body = Ox::Element.new("body").tap do |element|
    element[:xmlns]         = "http://jabber.org/protocol/httpbind"
    element["xmlns:xmpp"]   = "urn:xmpp:xbosh"
    element["xmpp:version"] = "1.0"
    element[:content]       = "text/xml; charset=utf-8"
    element[:rid]           = session.generate_next_rid
    element[:to]            = session.domain
    element[:secure]        = true
    element[:wait]          = 60
    element[:hold]          = 1
  end

  Jabber.debug(%Q[Open (rid="#{body.rid}") new session])

  response = session.post(Ox.dump body)
  xml = Ox.parse(response.body.tr("'", '"'))

  define_stream_mechanisms(xml)

  raise Jabber::XMLMalformedError,
    "Couldn't find <body /> attribute [sid]" if xml[:sid].nil?

  session.sid = xml.sid

  true
end

#pass_authentication(password) ⇒ Object

Internal: Send login request to jabber server

password - String the password of jabber user

Raises TypeError Raises XMLMalformedError Returns boolean

Raises:

  • (TypeError)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 59

def pass_authentication(password)
  # TODO : Define different exception type
  raise TypeError,
    "Server SASL mechanisms not include PLAIN mechanism" unless mechanisms.include?(:plain)

  body = Ox::Element.new("body").tap do |element|
    element[:xmlns]         = 'http://jabber.org/protocol/httpbind'
    element["xmpp:version"] = "1.0"
    element["xmlns:xmpp"]   = "urn:xmpp:xbosh"
    element[:content]       = "text/xml; charset=utf-8"
    element[:rid]           = session.generate_next_rid
    element[:sid]           = session.sid

    element << Query.new(session.jid, password, mechanism: :plain).to_ox
  end

  Jabber.debug(%Q[Authenticate {SASL} (rid="#{body.rid}" sid="#{body.sid}") in opened session] +
               %Q[ as #{session.jid.node}/#{session.jid.resource}])

  response = session.post(Ox.dump body)
  xml = Ox.parse(response.body.tr("'", '"'))

  return false if xml.locate("success").empty?

  true
end

#restart_streamObject



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/jabber4r/bosh/authentication/sasl.rb', line 86

def restart_stream
  body = Ox::Element.new("body").tap do |element|
    element[:xmlns]         = 'http://jabber.org/protocol/httpbind'
    element["xmlns:xmpp"]   = "urn:xmpp:xbosh"
    element["xmpp:version"] = "1.0"
    element["xmpp:restart"] = true
    element[:content]       = "text/xml; charset=utf-8"
    element[:rid]           = session.generate_next_rid
    element[:sid]           = session.sid
    element[:to]            = session.jid.domain
  end

  response = session.post(Ox.dump body)
  xml = Ox.parse(response.body.tr("'", '"'))

  return false if xml.locate("stream:features/bind").empty?

  true
end