File Coverage

blib/lib/SRS/EPP/Command/Login.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1              
2             package SRS::EPP::Command::Login;
3             {
4             $SRS::EPP::Command::Login::VERSION = '0.22';
5             }
6              
7 1     1   3525 use Moose;
  1         2  
  1         10  
8             extends 'SRS::EPP::Command';
9              
10 1     1   7569 use Crypt::Password qw();
  0            
  0            
11             use Data::Dumper;
12             use MooseX::Params::Validate;
13              
14             use XML::SRS::Types;
15              
16             with 'MooseX::Log::Log4perl::Easy';
17              
18             sub action {
19             "login";
20             }
21              
22             sub authenticated {0}
23              
24             has "uid" =>
25             is => "rw",
26             isa => "XML::SRS::RegistrarId",
27             ;
28              
29             has "server_id" =>
30             is => "rw",
31             isa => "Str",
32             lazy => 1,
33             default => sub {
34             my $self = shift;
35             $self->session->new_server_id;
36             },
37             ;
38              
39             has "session" =>
40             is => "rw",
41             isa => "SRS::EPP::Session",
42             weak_ref => 1,
43             ;
44              
45             has "password" =>
46             is => "rw",
47             isa => "Str",
48             ;
49              
50             has "login_ok" =>
51             is => "rw",
52             isa => "Bool",
53             ;
54              
55             has "new_password" =>
56             is => "rw",
57             isa => "Str",
58             ;
59              
60             sub process {
61             my $self = shift;
62            
63             my ( $session ) = pos_validated_list(
64             \@_,
65             { isa => 'SRS::EPP::Session' },
66             );
67            
68             $self->session($session);
69             my $epp = $self->message;
70             my $login = $epp->message->argument;
71             my $uid = $login->client_id;
72             if ( $uid !~ m{^\d+$} ) {
73             return $self->make_response(code => 2200);
74             }
75             $uid += 0; # remove leading 0's
76             $self->password($login->password);
77             $self->new_password($login->new_password)
78             if $login->new_password;
79             $self->uid($uid);
80             $self->session->want_user($uid);
81             $session->stalled($self);
82             my @rq_services = $login->services;
83             my @rq_extensions = $login->extensions
84              
85             if $login->has_ext_services;
86              
87             for my $rq_service (@rq_services) {
88             if ( !$XML::EPP::obj_uris{$rq_service} ) {
89             return $self->make_error(
90             code => 2307,
91             value => $rq_service,
92             reason => "This object service is not available on this server",
93             );
94             }
95             }
96              
97             for my $rq_ext (@rq_extensions) {
98             if ( !$XML::EPP::ext_uris{$rq_ext} ) {
99             return $self->make_error(
100             code => 2307,
101             value => $rq_ext,
102             reason => "This extension is not available on this server",
103             );
104             }
105             }
106            
107             $session->extensions->set(@rq_extensions);
108              
109             return (
110             XML::SRS::Registrar::Query->new(
111             registrar_id => $uid,
112             ),
113             XML::SRS::ACL::Query->new(
114             Resource => "epp_connect",
115             List => "whitelist",
116             Type => "registrar_ip",
117             filter_types => ["AddressFilter", "RegistrarIdFilter"],
118             filter => [$session->peerhost, $uid],
119             ),
120             (
121             $session->proxy->rfc_compliant_ssl
122             ? (
123             XML::SRS::ACL::Query->new(
124             Resource => "epp_client_certs",
125             List => "whitelist",
126             Type => "registrar_domain",
127             filter_types => ["DomainNameFilter", "RegistrarIdFilter"],
128             filter => [$session->peer_cn, $uid],
129             )
130             )
131             : ()
132             ),
133             );
134             }
135              
136             sub notify{
137             my $self = shift;
138            
139             my ( $rs ) = pos_validated_list(
140             \@_,
141             { isa => 'ArrayRef[SRS::EPP::SRSResponse]' },
142             );
143            
144             if ( @$rs > 1 ) {
145              
146             # response to login
147             my $registrar = $rs->[0];
148             my $ip_ok_acl = $rs->[1];
149             my $cn_ok_acl = $rs->[2];
150              
151             # fail by default
152             $self->login_ok(0);
153              
154             # check the password
155             my $password_ok;
156             if (
157             my $auth = eval {
158             $registrar->message->response->epp_auth
159             }
160             )
161             {
162             $self->log_debug(
163             "checking provided password ("
164             .$self->password
165             .") against "
166             .Dumper(
167             $auth->crypted
168             )
169             );
170             $password_ok = Crypt::Password::password($auth->crypted)->check($self->password);
171             $self->log_info("supplied password does not match")
172             if !$password_ok;
173             }
174             else {
175             $self->log_info("could not fetch password (denying login): $@");
176             }
177              
178             # must be an entry on the allow list
179             my $ip_ok;
180             if (
181             my $entry = eval {
182             $ip_ok_acl->message->response->entries->[0]
183             }
184             )
185             {
186             $ip_ok = 1;
187             $self->log_info("IP ACL found for ".$entry->Address);
188             }
189             else {
190             $self->log_info("no IP ACL found; denying login");
191             }
192              
193             # the certificate must also have an entry
194             my $cn_ok = $cn_ok_acl ? 0 : 1;
195             if (
196             $cn_ok_acl && (
197             my $entry = eval {
198             $cn_ok_acl->message->response->entries->[0];
199             }
200             )
201             )
202             {
203             $self->log_info(
204             "Domain ACL found for: "
205             .$entry->DomainName
206             );
207             $cn_ok = 1;
208             }
209             else {
210             $self->log_info("no common name ACL found; denying login");
211             }
212              
213             if ( $password_ok and $ip_ok and $cn_ok ) {
214             $self->log_info("login as registrar ".$self->uid." successful");
215             $self->login_ok(1);
216             $self->session->user($self->uid);
217             }
218             else {
219             $self->log_info("login as registrar ".$self->uid." unsuccessful");
220             }
221             $self->session->clear_want_user;
222             $self->session->stalled(0);
223              
224             # Wrap it up...
225             if ( $self->login_ok ) {
226             if ( $self->new_password() ) {
227             return XML::SRS::Registrar::Update->new(
228             registrar_id => $self->uid,
229             epp_auth => $self->new_password,
230             action_id => $self->server_id,
231             );
232             }
233             return $self->make_response(code => 1000);
234             }
235             return $self->make_response(code => 2200);
236             }
237             else {
238              
239             # response to a password update
240             my $registrar = $rs->[0];
241             if (
242             my $auth = eval {
243             $registrar->message->response->epp_auth
244             }
245             )
246             {
247             my $ok = Crypt::Password::password($auth->crypted)->check($self->new_password);
248             if ($ok) {
249             $self->log_info("changed password successfully");
250             return $self->make_response(code => 1000);
251             }
252             else {
253             $self->log_error("failed to change password!");
254             return $self->make_response(code => 2400);
255             }
256             }
257             }
258              
259             }
260              
261             1;