Changeset 851

Show
Ignore:
Timestamp:
02/11/09 21:57:06 (10 months ago)
Author:
ykerherve
Message:

Finished resource conflit handling per RFC 3920
this introduced a medium change in the way DJabberd
do JID registration. Now, register_jid takes a bare_jid and
a resource instead of a fulljid so that we can generate a
resource in case of conflict as RECOMMENDED. XEP 0078 behaviour
is kept unchanged though.

Location:
trunk/DJabberd
Files:
5 modified

Legend:

Unmodified
Added
Removed
  • trunk/DJabberd/lib/DJabberd/Bot.pm

    r795 r851  
    5252sub register { 
    5353    my ($self, $vhost) = @_; 
    54     $self->{jid} = DJabberd::JID->new("$self->{nodename}\@" . $vhost->server_name . "/$self->{resource}"); 
     54    my $barejid = DJabberd::JID->new("$self->{nodename}\@" . $vhost->server_name ); 
     55    my $resource = $self->{resource}; 
    5556 
    5657    $self->{vhost} = $vhost; 
    5758    Scalar::Util::weaken($self->{vhost}); 
    5859 
     60    my $reg_jid; 
    5961    my $regcb = DJabberd::Callback->new({ 
    6062        registered => sub { 
    61             $logger->debug("Bot $self->{jid} is now registered"); 
     63            (undef, my $reg_jid) = @_; 
     64            $logger->debug("Bot $reg_jid is now registered"); 
    6265        }, 
    6366        error => sub { 
    64             $logger->error("Bot $self->{jid} failed to register"); 
     67            $logger->error("Bot $barejid/$resource failed to register"); 
    6568            }, 
    6669    }); 
    6770 
    68     $vhost->register_jid($self->{jid}, $self , $regcb); 
    69     DJabberd::Presence->set_local_presence( 
    70         $self->{jid},  
    71         DJabberd::Presence->available( from => $self->{jid} ) 
    72     ); 
     71    $vhost->register_jid($barejid, $resource, $self, $regcb); 
     72    if ($reg_jid) { 
     73        $self->{jid} = $reg_jid; 
     74        DJabberd::Presence->set_local_presence( 
     75            $self->{jid}, 
     76            DJabberd::Presence->available( from => $self->{jid} ) 
     77        ); 
     78    } 
    7379} 
    7480 
  • trunk/DJabberd/lib/DJabberd/IQ.pm

    r849 r851  
    496496    my $digest   = $get->("digest"); 
    497497 
    498     return unless $username =~ /^\w+$/; 
     498    # "Both the username and the resource are REQUIRED for client 
     499    # authentication" Section 3.1 of XEP 0078 
     500    return unless $username && $username =~ /^\w+$/; 
     501    return unless $resource; 
    499502 
    500503    my $vhost = $conn->vhost; 
     
    518521 
    519522        # register 
    520         my $jid = DJabberd::JID->new("$authjid/$resource"); 
     523        my $jid = DJabberd::JID->new("$authjid"); 
    521524 
    522525        unless ($jid) { 
     
    527530        my $regcb = DJabberd::Callback->new({ 
    528531            registered => sub { 
    529                 $conn->set_bound_jid($jid); 
     532                (undef, my $fulljid) = @_; 
     533                $conn->set_bound_jid($fulljid); 
    530534                $DJabberd::Stats::counter{'auth_success'}++; 
    531535                $iq->send_result; 
     
    540544        }); 
    541545 
    542         $vhost->register_jid($jid, $conn, $regcb); 
     546        $vhost->register_jid($jid, $resource, $conn, $regcb); 
    543547    }; 
    544548 
     
    627631    }; 
    628632 
    629     my $resource = $get->("resource") 
    630                  || Digest::SHA1::sha1_hex(rand() . rand() . rand()); 
     633    my $resource = $get->("resource") || DJabberd::JID->rand_resource; 
    631634 
    632635    my $vhost = $conn->vhost; 
     
    669672 
    670673    # register 
    671     my $jid = DJabberd::JID->new("$authjid/$resource"); 
     674    my $jid = DJabberd::JID->new($authjid); 
    672675 
    673676    unless ($jid) { 
     
    678681    my $regcb = DJabberd::Callback->new({ 
    679682        registered => sub { 
    680             $conn->set_bound_jid($jid); 
     683            (undef, my $fulljid) = @_; 
     684            $conn->set_bound_jid($fulljid); 
    681685            $DJabberd::Stats::counter{'auth_success'}++; 
    682686            my $xml = <<EOX; 
    683 <iq id='$id' type='result'> 
     687<iq id='$fulljid' type='result'> 
    684688    <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> 
    685         <jid>$jid</jid> 
     689        <jid>$fulljid</jid> 
    686690    </bind> 
    687691</iq> 
     
    699703    }); 
    700704 
    701     $vhost->register_jid($jid, $conn, $regcb); 
     705    $vhost->register_jid($jid, $resource, $conn, $regcb); 
    702706    return 1; 
    703707} 
  • trunk/DJabberd/lib/DJabberd/JID.pm

    r672 r851  
    22use strict; 
    33use DJabberd::Util qw(exml); 
     4use Digest::SHA1; 
    45 
    56use overload 
     
    7677} 
    7778 
     79sub rand_resource { 
     80    Digest::SHA1::sha1_hex(rand() . rand() . rand()); 
     81} 
     82 
    78831; 
    7984 
  • trunk/DJabberd/lib/DJabberd/VHost.pm

    r841 r851  
    55use DJabberd::Util qw(tsub as_bool); 
    66use DJabberd::Log; 
     7use DJabberd::JID; 
    78use DJabberd::Roster; 
    89 
     
    364365 
    365366sub register_jid { 
    366     my ($self, $jid, $conn, $cb) = @_; 
     367    my ($self, $jid, $resource, $conn, $cb) = @_; 
     368 
     369    my $barestr = $jid->as_bare_string; ## $jid should be bare anyway 
     370    my $fullstr = "$barestr/$resource"; 
     371 
    367372    # $cb can ->registered, ->error 
    368     $logger->info("Registering '$jid' to connection '$conn->{id}'"); 
    369  
    370     my $barestr = $jid->as_bare_string; 
    371     my $fullstr = $jid->as_string; 
    372  
     373    $logger->info("Registering '$fullstr' to connection '$conn->{id}'"); 
     374 
     375    ## deprecated 0078 appears a bit conflicting with RFC 3920 
     376    ## the recommended behaviour in the latter is to generate a resource for 
     377    ## the dupe. Don't ask me if one resource uses RFC 3920 and the other 
     378    ## XEP 0078 :D. If we detect a sasl connection, we go with the RFC way. 
    373379    if (my $econn = $self->{jid2sock}{$fullstr}) { 
    374         $econn->stream_error("conflict"); 
    375     } 
     380        if ($conn->sasl) { 
     381            my $resource = DJabberd::JID->rand_resource; 
     382            $fullstr = "$barestr/$resource"; 
     383        } 
     384        else { 
     385            $econn->stream_error("conflict"); 
     386        } 
     387    } 
     388    my $fulljid = DJabberd::JID->new($fullstr); 
    376389 
    377390    $self->{jid2sock}{$fullstr} = $conn; 
    378391    ($self->{bare2fulls}{$barestr} ||= {})->{$fullstr} = 1;  # TODO: this should be the connection, not a 1, saves work in unregister JID? 
    379392 
    380     $cb->registered; 
     393    $cb->registered($fulljid); 
    381394} 
    382395 
  • trunk/DJabberd/t/sasl-login.t

    r850 r851  
    6666{ 
    6767    two_parties(sub { 
    68         my ($pa, $pb) = @_; 
     68        my ($pa1, $pb) = @_; 
     69        my $conflicted_res = "yann"; 
    6970 
     71        my $pa2 = Test::DJabberd::Client->new(server   => $pa1->server, 
     72                                              name     => $pa1->username, 
     73                                              resource => $conflicted_res, 
     74                                            ); 
    7075        my $sasl = Authen::SASL->new( 
    7176            mechanism => "DIGEST-MD5", 
    7277            callback  => { 
    73                 pass => sub { $pa->password }, 
    74                 user => sub { $pa->{name}   }, 
     78                pass => sub { $pa1->password }, 
     79                user => sub { $pa1->{name}   }, 
    7580            }, 
    7681        ); 
    77         my $pa_res = $pa->sasl_login($sasl, "yann")->resource; 
    78         my $pb_res = $pb->sasl_login($sasl, "yann")->resource; 
    79         cmp_ok $pa_res, 'ne', $pb_res, "resources are different"; 
    80         is   $pa_res, "yann", "first got what it wanted"; 
    81         isnt $pb_res, "yann", "second didn't"; 
     82        my $pa1_res = $pa1->sasl_login($sasl, $conflicted_res)->resource; 
     83 
     84        my $pa2_res = $pa2->sasl_login($sasl, $conflicted_res)->resource; 
     85        cmp_ok $pa1_res, 'ne', $pa2_res, "resources are different"; 
     86        is   $pa1_res, $conflicted_res, "first got what it wanted"; 
     87        isnt $pa2_res, $conflicted_res, "second didn't"; 
    8288    }); 
    8389}