1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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 51 52 53 54 55 56 57 58 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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
# Copyright (c) 2003 Graham Barr, Djamel Boudjerda, Paul Connolly, Julian Onions and Nexor.
# All rights reserved. This program is free software; you can redistribute
# it and/or modify it under the same terms as Perl itself.
# See http://www.ietf.org/rfc/rfc2831.txt for details
package Authen::SASL::Perl::DIGEST_MD5;
use strict;
use vars qw($VERSION @ISA $CNONCE);
use Digest::MD5 qw(md5_hex md5);
$VERSION = "1.04";
@ISA = qw(Authen::SASL::Perl);
my %secflags = (
noplaintext => 1,
noanonymous => 1,
);
# some have to be quoted - some don't - sigh!
my %qdval; @qdval{qw(username authzid realm nonce cnonce digest-uri)} = ();
sub _order { 3 }
sub _secflags {
shift;
scalar grep { $secflags{$_} } @_;
}
sub mechanism { 'DIGEST-MD5' }
# no initial value passed to the server
sub client_start {
'';
}
sub client_step # $self, $server_sasl_credentials
{
my ($self, $challenge) = @_;
$self->{server_params} = \my %sparams;
# Parse response parameters
while($challenge =~ s/^(?:\s*,)?\s*(\w+)=("([^\\"]+|\\.)*"|[^,]+)\s*//) {
my ($k, $v) = ($1,$2);
if ($v =~ /^"(.*)"$/s) {
($v = $1) =~ s/\\//g;
}
$sparams{$k} = $v;
}
return $self->set_error("Bad challenge: '$challenge'")
if length $challenge;
return $self->set_error("Server does not support auth (qop = $sparams{'qop'})")
unless grep { /^auth$/ } split(/,/, $sparams{'qop'});
my %response = (
nonce => $sparams{'nonce'},
username => $self->_call('user'),
realm => $sparams{'realm'},
nonce => $sparams{'nonce'},
cnonce => md5_hex($CNONCE || join (":", $$, time, rand)),
'digest-uri' => $self->service . '/' . $self->host,
qop => 'auth',
nc => sprintf("%08d", ++$self->{nonce}{$sparams{'nonce'}}),
charset => $sparams{'charset'},
);
my $authzid = $self->_call('authname');
if (defined $authzid) {
$response{authzid} = $authzid;
}
my $serv_name = $self->_call('serv');
if (defined $serv_name) {
$response{'digest_uri'} .= '/' . $serv_name;
}
my $password = $self->_call('pass');
# Generate the response value
my $A1 = join (":",
md5(join (":", @response{qw(username realm)}, $password)),
@response{defined($authzid) ? qw(nonce cnonce authzid) : qw(nonce cnonce)}
);
my $A2 = "AUTHENTICATE:" . $response{'digest-uri'};
$A2 .= ":00000000000000000000000000000000"
if $response{'qop'} and $response{'qop'} =~ /^auth-(conf|int)$/;
$response{'response'} = md5_hex(
join (":", md5_hex($A1), @response{qw(nonce nc cnonce qop)}, md5_hex($A2))
);
join (",", map { _qdval($_, $response{$_}) } sort keys %response);
}
sub _qdval {
my ($k, $v) = @_;
if (!defined $v) {
return;
}
elsif (exists $qdval{$k}) {
$v =~ s/([\\"])/\\$1/g;
return qq{$k="$v"};
}
return "$k=$v";
}
1;
__END__
=head1 NAME
Authen::SASL::Perl::DIGEST_MD5 - Digest MD5 Authentication class
=head1 SYNOPSIS
use Authen::SASL qw(Perl);
$sasl = Authen::SASL->new(
mechanism => 'DIGEST-MD5',
callback => {
user => $user,
pass => $pass,
serv => $serv
},
);
=head1 DESCRIPTION
This method implements the client part of the DIGEST-MD5 SASL algorithm,
as described in RFC-2831.
This module only implements the I<auth> operation which offers authentication
but neither integrity protection not encryption.
=head2 CALLBACK
The callbacks used are:
=over 4
=item authname
The authorization id to use after successful authentication
=item user
The username to be used in the response
=item pass
The password to be used in the response
=item serv
The service name when authenticating to a replicated service
=back
=head1 SEE ALSO
L<Authen::SASL>,
L<Authen::SASL::Perl>
=head1 AUTHORS
Graham Barr, Djamel Boudjerda (NEXOR) Paul Connolly, Julian Onions (NEXOR)
Please report any bugs, or post any suggestions, to the perl-ldap mailing list
<perl-ldap-dev@perl.org>
=head1 COPYRIGHT
Copyright (c) 2003 Graham Barr, Djamel Boudjerda, Paul Connolly, Julian Onions
and Nexor.
All rights reserved. This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
=cut
|