ejabberd BOSH search brings nothing

2020-05-07 05:51发布

问题:

We're trying to switch from Openfire to ejabberd XMPP server. I have ejabberd installed with default options on my local Windows 10 workstation. I set

  mod_vcard:
    search: true

I registered a couple of users using ejabberd ReST API. I also set some vcard values for those users (my understanding is that vcard entries are necessary for ejabberd search to work, correct?) Using Postman, I can confirm that there are vcards for user "testfouoles":

POST http://localhost:5281/api/get_vcard
Body:
{
      "host": "planetrisk.com",
      "user": "testfouoles",
      "name": "FN"
}

Response:
{
    "content": "Test UnclassifiedFouoLes"
}

Besides FN, EMAIL, NICKNAME, and NICK vcards are set. vcards seems to be case-sensitive, so I set both small lettters and capital letters variants, because I'm not sure which variants are used by search. I also set vcard2 values for N FAMILY and N GIVEN.

For Openfire, we were using CandyJs with a custom Search plugin. For now we continue to use it with ejabberd. For test purposes, I set

  mod_vcard:
    search: true
    allow_return_all: true

This way, search operations with empty input fields return all users who added some information to their vCard (according to ejabberd docs).

Our CandyJS Search plugin issues the following POST request to ejabberd BOSH listener:

Request URL:http://localhost:5443/bosh?b=101
Request Method:POST
Status Code:200 OK
Remote Address:127.0.0.1:5443
...
Request Payload
<body rid='55271928' xmlns='http://jabber.org/protocol/httpbind' sid='5633a7a6184041b173970798227fddadea5e8742'>
  <iq type='set' id='search2' to='vjud.planetrisk.com' xmlns='jabber:client'>
    <query xmlns='jabber:iq:search'>
      <x xmlns='jabber:x:data' type='submit'>
        <field var='first'><value/></field>
        <field var='last'><value/></field>
        <field var='nick'><value/></field>
        <field var='email'><value/></field>
        <field var='fn'><value/></field>
      </x>
    </query>
  </iq>
</body>

And ejabberd responds with vcard data of the only registered user (besides the requesting user):

<body xmlns='http://jabber.org/protocol/httpbind'>
  <iq xml:lang='en' to='army.dudeFOUO(at)everbridge.mil@planetrisk.com/planetrisk_Candy_b4a02de8' from='vjud.planetrisk.com' type='result' id='search2' xmlns='jabber:client'>
    <query xmlns='jabber:iq:search'>
      <x type='result' xmlns='jabber:x:data'>
        <title>Search Results for vjud.planetrisk.com</title>
        <reported>
          <field var='jid' type='text-single' label='Jabber ID'/>
          <field var='fn' type='text-single' label='Full Name'/>
          <field var='first' type='text-single' label='Name'/>
          <field var='middle' type='text-single' label='Middle Name'/>
          <field var='last' type='text-single' label='Family Name'/>
          <field var='nick' type='text-single' label='Nickname'/>
          <field var='bday' type='text-single' label='Birthday'/>
          <field var='ctry' type='text-single' label='Country'/>
          <field var='locality' type='text-single' label='City'/>
          <field var='email' type='text-single' label='Email'/>
          <field var='orgname' type='text-single' label='Organization Name'/>
          <field var='orgunit' type='text-single' label='Organization Unit'/>
        </reported>
        <item>
          <field var='jid'><value>testfouoles@planetrisk.com</value></field>
          <field var='fn'><value>Test UnclassifiedFouoLes</value></field>
          <field var='last'><value>UnclassifiedFouoLes</value></field>
          <field var='first'><value>Test</value></field>
          <field var='middle'><value/></field>
          <field var='nick'><value>testfouoles</value></field>
          <field var='bday'><value/></field>
          <field var='ctry'><value/></field>
          <field var='locality'><value/></field>
          <field var='email'><value>testfouoles@planetrisk.com</value></field>
          <field var='orgname'><value/></field>
          <field var='orgunit'><value/></field>
        </item>
      </x>
    </query>
  </iq>
</body>

Everything works fine so far. Now, if I submit a search request with non-empty search criteria, regardless of having allow_return_all: true or false, search does not find anything:

Request Payload
<body rid='839156118' xmlns='http://jabber.org/protocol/httpbind' sid='39d0d2e120960757f97eeb15488ba6820b509bf7'>
  <iq type='set' id='search2' to='vjud.planetrisk.com' xmlns='jabber:client'>
    <query xmlns='jabber:iq:search'>
      <x xmlns='jabber:x:data' type='submit'>
        <field var='first'><value>UnclassifiedFouoLes</value></field>
        <field var='last'><value>UnclassifiedFouoLes</value></field>
        <field var='nick'><value>UnclassifiedFouoLes</value></field>
        <field var='email'><value>UnclassifiedFouoLes</value></field>
        <field var='fn'><value>UnclassifiedFouoLes</value></field>
      </x>
    </query>
  </iq>
</body>

Here I tried to search for "UnclassifiedFouoLes" which is the correct value of N FAMILY. I tried to search for correct email, nick, etc - nothing works. ejabberd returns an empty result.

<body xmlns='http://jabber.org/protocol/httpbind'>
  <iq xml:lang='en' to='army.dudeFOUO(at)everbridge.mil@planetrisk.com/planetrisk_Candy_0d46391c' from='vjud.planetrisk.com' type='result' id='search2' xmlns='jabber:client'>
    <query xmlns='jabber:iq:search'>
      <x type='result' xmlns='jabber:x:data'>
        <title>Search Results for vjud.planetrisk.com</title>
        <reported>
          <field var='jid' type='text-single' label='Jabber ID'/>
          <field var='fn' type='text-single' label='Full Name'/>
          <field var='first' type='text-single' label='Name'/>
          <field var='middle' type='text-single' label='Middle Name'/>
          <field var='last' type='text-single' label='Family Name'/>
          <field var='nick' type='text-single' label='Nickname'/>
          <field var='bday' type='text-single' label='Birthday'/>
          <field var='ctry' type='text-single' label='Country'/>
          <field var='locality' type='text-single' label='City'/>
          <field var='email' type='text-single' label='Email'/>
          <field var='orgname' type='text-single' label='Organization Name'/>
          <field var='orgunit' type='text-single' label='Organization Unit'/>
        </reported>
      </x>
    </query>
    </iq>
  </body>

So, why doesn't ejabberd find users by correctly supplied (?) search terms which matches vcard values? What am I doing wrong?

I'm stuck. I cannot find any additional ejabberd documentation on Jabber Search. I don't understand how standard vcard field names correspond to standard Jabber Search field names (or maybe Data Forms field names?).

The same CandyJS Search plugin issues very similar request to Openfire XMPP server and gets results. The only difference is that Openfire requires some non-standard additions to search request payload to specify in which fields to search in:

<field var='Username'><value>1</value></field>
<field var='Name'><value>1</value></field>
<field var='Email'><value>1</value></field>

And Openfire returns results with an additional

<field var="FORM_TYPE" type="hidden"/>

clause. Does it give any clue?

I'm stuck and really appreciate pointing me to the right direction.

Update:

Actually, here is the first question: When we send the following search request to XMPP server

<body rid='839156118' xmlns='http://jabber.org/protocol/httpbind'
sid='39d0d2e120960757f97eeb15488ba6820b509bf7'>
  <iq type='set'id='search2' to='vjud.planetrisk.com' xmlns='jabber:client'>
    <query xmlns='jabber:iq:search'>
      <x xmlns='jabber:x:data' type='submit'>
        <field var='first'><value>UnclassifiedFouoLes</value></field>
        <field var='last'><value>UnclassifiedFouoLes</value></field>
        <field var='nick'><value>UnclassifiedFouoLes</value></field>
        <field var='email'><value>UnclassifiedFouoLes</value></field>
        <field var='fn'><value>UnclassifiedFouoLes</value></field>
      </x>
    </query>
 </iq>
</body>

Are search conditions combined by "OR" or by "AND"? Do we search for a user who has any of field values ('first', 'last', 'nick', email', 'fn') equal to 'UnclassifiedFouoLes' or all the fields equal?

Update 2: I'm trying to send a simple request (one without <x xmlns='jabber:x:data' type='submit'>) from Postman to ejabberd:

<body rid='1106091871' xmlns='jabber.org/protocol/httpbind' sid='2afabe5b07c316685e25a2d407617a534ca6b2bb'>
  <iq type='set' id='search2' to='vjud.planetrisk.com' xmlns='jabber:client'>
    <query xmlns='jabber:iq:search'><last>UnclassifiedFouoLes</last></query>
  </iq>
</body>

The result is always empty - it doesn't return any items. And there is a user with "last" vCard = "UnclassifiedFouoLes".

Why is it? Is "from" clause in request required?

Two existing clients can see each other and communicate in chat. But when I login as client1, grab sid and rid, insert them into Postman post, result is empty like

<body xmlns='http://jabber.org/protocol/httpbind' sid='67c6c7ee389a99e3491bbeab9ab198766ffa5ca8' rid='1287825358'>
    <iq xmlns='jabber:client' type='set' id='search2' to='vjud.planetrisk.com'>
        <query xmlns='jabber:iq:search'>
            <last>UnclassifiedFouoLes</last>
        </query>
    </iq>
</body>

回答1:

Simple type of search (one without <x xmlns="jabber:x:data" type="submit">) somehow returned error.

For extended search, it turned out, I was not sending

<field type="hidden" var="FORM_TYPE"><value>jabber:iq:search</value></field>

clause. That omission was working fine against Openfire, ejabberd requires it.

Still, Openfire Search plugin provides convenience and efficiency which I didn't find in ejabberd: it allows a chat client to display one search box and then to search for the value user typed in several fields (search OR functionality). On a client side, you need to send search request like

<body rid='273260412' xmlns='http://jabber.org/protocol/httpbind' sid='961w8ipmo2'>
  <iq type='set' id='search2' to='yourSearchDomain.com' xmlns='jabber:client'>
    <query xmlns='jabber:iq:search'>
      <x xmlns='jabber:x:data' type='submit'>
        <field var='search'><value>your_search_term</value></field>
        <field var='Username'><value>1</value></field>
        <field var='Name'><value>1</value></field>
        <field var='Email'><value>1</value></field>
      </x>
    </query>
  </iq>
</body>

Openfire Search plugin would interpret this request as a command to perform three search requests: to find users with Username which matches your_search_term, then to find users with Name matching, and with Email matching. All three search results would be combined using logical OR.
Client only needs to send one Http search request to Openfire to search for your_search_term in three fields. With ejabberd, client would need to send three Http requests...

It would be nice to implement similar functionality in ejabberd module...