1package Mango::Auth::SCRAM; 2 3use Mojo::Base 'Mango::Auth'; 4use Mojo::Util qw(dumper md5_sum encode b64_encode b64_decode); 5use Mango::BSON 'bson_doc'; 6 7EVAL: { 8 local $@; 9 die "Authen::SCRAM is required to use SCRAM-SHA-1\n" 10 unless eval { require Authen::SCRAM::Client; 1 }; 11} 12 13sub _credentials { 14 my ($self, $creds) = @_; 15 16 # [db, user, pass] 17 $creds->[2] 18 = md5_sum(encode("UTF-8", $creds->[1] . ":mongo:" . $creds->[2])); 19 $self->{credentials} = $creds; 20} 21 22sub _authenticate { 23 my ($self, $id) = @_; 24 25 my $mango = $self->mango; 26 my $cnx = $self->mango->{connections}{$id}; 27 my $creds = $self->{credentials}; 28 29 my ($db, $user, $pass) = @$creds; 30 31 my $scram_client = Authen::SCRAM::Client->new( 32 skip_saslprep => 1, 33 username => $user, 34 password => $pass 35 ); 36 37 my $delay = Mojo::IOLoop::Delay->new; 38 my $conv_id; 39 40 $delay->steps( 41 sub { 42 my ($d, $mango, $err, $doc) = @_; 43 $conv_id = $doc->{conversationId}; 44 my $final_msg = $scram_client->final_msg(b64_decode $doc->{payload}); 45 46 my $command = $self->_cmd_sasl_continue($conv_id, $final_msg); 47 $mango->_fast($id, $db, $command, $d->begin(0)); 48 }, 49 sub { 50 my ($d, $mango, $err, $doc) = @_; 51 $scram_client->validate(b64_decode $doc->{payload}); 52 53 my $command = $self->_cmd_sasl_continue($conv_id, ''); 54 $mango->_fast($id, $db, $command, $d->begin(0)); 55 }, 56 sub { 57 my ($d, $mango, $err, $doc) = @_; 58 $mango->emit(connection => $id)->_next; 59 } 60 ); 61 62 my $command = $self->_cmd_sasl_start($scram_client->first_msg); 63 $mango->_fast($id, $db, $command, $delay->begin(0)); 64 65 $delay->wait; 66 $delay->ioloop->one_tick unless $delay->ioloop->is_running; 67} 68 69sub _cmd_sasl_start { 70 my ($self, $first_msg) = @_; 71 72 bson_doc( 73 'saslStart' => 1, 74 'mechanism' => 'SCRAM-SHA-1', 75 'payload' => b64_encode($first_msg, ''), 76 'autoAuthorize' => 1, 77 ); 78} 79 80sub _cmd_sasl_continue { 81 my ($self, $conv_id, $final_msg) = @_; 82 83 bson_doc( 84 'saslContinue' => 1, 85 'conversationId' => $conv_id, 86 'payload' => $final_msg ? b64_encode($final_msg, '') : '' 87 ); 88} 89 901; 91 92=encoding utf8 93 94=head1 NAME 95 96Mango::Auth::SCRAM - SCRAM-SHA-1 Authentication 97 98=head1 DESCRIPTION 99 100The default authentication backend for L<Mango> using the SCRAM-SHA-1 algorithm. 101It requires L<Authen::SCRAM>. 102 103=head1 SEE ALSO 104 105L<Mango>, L<Mojolicious::Guides>, L<http://mojolicio.us>. 106 107=cut 108