1package DJabberd::SASL; 2use strict; 3use warnings; 4 5use base qw/DJabberd::Plugin/; 6 7use DJabberd::Stanza::SASL; 8use DJabberd::SASL::Connection; 9use DJabberd::Util qw(as_bool); 10 11my $default = "DJabberd::SASL::Manager::AuthenSASL"; 12sub manager_class { $default } 13 14my $sasl_ns = "urn:ietf:params:xml:ns:xmpp-sasl"; 15my %sasl_elements = ( 16 "{$sasl_ns}auth" => 'DJabberd::Stanza::SASL', 17 "{$sasl_ns}challenge" => 'DJabberd::Stanza::SASL', 18 "{$sasl_ns}response" => 'DJabberd::Stanza::SASL', 19 "{$sasl_ns}abort" => 'DJabberd::Stanza::SASL', 20); 21 22sub get_sasl_manager { 23 my $self = shift; 24 my $conn = shift; 25 26 my $vhost = $conn->vhost 27 or die "No VHost for this connection"; 28 29 my $class = $self->manager_class || $default; 30 31 no strict 'refs'; 32 unless (defined %{"${class}::"}) { 33 eval "use $class"; ## no critic 34 die $@ if $@; 35 } 36 37 return $class->new($self, $conn); 38} 39 40sub set_config_optional { 41 my ($self, $val) = @_; 42 $self->{optional} = as_bool($val); 43} 44 45sub is_optional { return $_[0]->{optional} ? 1 : 0 } 46 47sub mechanisms { die "implement" } 48 49sub mechanisms_str { 50 my $plugin = shift; 51 return join " ", $plugin->mechanisms; 52} 53 54sub mechanisms_list { 55 my $plugin = shift; 56 return keys %{ $plugin->mechanisms }; 57} 58 59 60## don't override, or be sure to call SUPER:: in the subclass 61sub register { 62 my ($plugin, $vhost) = @_; 63 64 $vhost->register_hook("GetSASLManager", sub { 65 my (undef, $cb, %args) = @_; 66 my $conn = $args{conn}; 67 my $sasl = $plugin->get_sasl_manager($conn); 68 $cb->get($sasl); 69 }); 70 71 $vhost->register_hook("HandleStanza", sub { 72 my (undef, $cb, $node) = @_; 73 my $class = $sasl_elements{$node->element}; 74 return unless $class; 75 $cb->handle($class); 76 return; 77 }); 78} 79 801; 81 82__END__ 83 84=pod 85 86=head1 NAME 87 88DJabberd::SASL - Base plugin for SASL Negotiation 89 90=head1 DESCRIPTION 91 92This base plugin just provides the skeleton necessary for building SASL layers 93within DJabberd. It provides one hook (GetSASLManager) to initiate the SASL 94negotiation and return a SASL Manager object; and it hooks the SASL stanzas 95to the default L<DJabberd::Stanza::SASL> class. 96 97See L<DJabberd::SASL::AuthenSASL> for a concrete plugin based on 98I<DJabberd::SASL>. 99 100=head1 HOW DOES THE DEFAULT SASL INFRASTRUCTURE WORK 101 102When a I<DJabberd::SASL> subclass is declared inside of a B<VHost>, it enables 103SASL negotiation for the connection. 104 105What does that mean is that SASL will be advertised in the stream features. 106Then, when the client sends a SASL stanza (see RFC 3920), they are handled 107using L<DJabberd::Stanza::SASL> class, which makes a few assumption: 108 109=over 4 110 111=item * The plugin supports the I<GetSASLManager> hook that returns a 112L<DJabberd::SASL::ManagerBase> subclass. 113 114=item * The interface to this manager and to the sasl connection 115object (see later) is a superset of L<Authen::SASL> interface. 116 117=back 118 119From there, the SASL negotiation is in the hands of the configured SASL Manager. 120 121One configuration option is common to all plugins: This is C<Optional> which 122advertises to the client if SASL is optional or not. By default SASL is (and 123should be) required. 124 125=head1 SYNOPSIS 126 127 <VHost yann.cyberion.net> 128 <Plugin DJabberd::SASL::%Subclass%> 129 Optional yes 130 %Config% 131 </Plugin> 132 </VHost> 133 134=head1 EXTENDING SASL IN DJABBERD 135 136See examples. 137 138It's fairly easy to extend the SASL phase with anything you like provided the 139simple L<DJabberd::SASL::ManagerBase> and L<DJabberd::SASL::Connection> which 140are based on L<Authen::SASL> are repected. 141 142Alternatively since this is just a plugin, you can also throw it away 143altogether and write something from scratch. You'll have to provide a new set 144of handlers for the SASL stanzas though (in replacement of 145L<DJabberd::Stanzas::SASL>. 146 147=head1 COPYRIGHT 148 149(c) 2009 Yann Kerherve 150 151This module is part of the DJabberd distribution and is covered by the 152distribution's overall licence. 153 154=cut 155 156# Local Variables: 157# mode: perl 158# c-basic-indent: 4 159# indent-tabs-mode: nil 160# End: 161