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