Catalyst Debug Log Filtering
Catalyst has awesome debug logging. I love it. I’ve done great things with it (the topic of a future post). But partly because of those great things (hint: we keep these logs around and make them available for tech support and QA), this is a problem:
[debug] Body Parameters are: .---------------------------+----------------------------. | Parameter | Value | +---------------------------+----------------------------+ | password | supersecret | | user | some_user | '---------------------------+----------------------------'
As it turns out, there’s a module out there, CatalystX::DebugFilter, which does a good job of scrubbing a variety of configurable things out of a variety of configurable places. However, if you take a look at the source code of this module, you’ll find it’s rather… complex. It does a complex thing, and in a complex way. And along the way, it invokes Clone. This has caused no end of problems for my project. Everything from Rose::DB warnings (cloning database handles leads to Bad Things) to crashing Perl. We’ve found crazy workarounds, but in the end it became clear that we just had to replace this module with something a lot less complex. It’s a simple need we have, and a simple solution will suffice. Here’s my replacement:
package Adama::DebugFilter;
# Scrub passwords from the debug logging
use Moose::Role;
use namespace::autoclean;
requires('log_request_parameters');
around log_request_parameters => sub {
my $next = shift;
my $c = shift;
my %all_params = @_;
my %out_params;
foreach my $type (keys %all_params) {
my $in_params = $all_params{$type};
my %params;
$params{$_} = $_ eq "password" ? "[FILTERED]" : $in_params->{$_}
foreach keys %$in_params;
$out_params{$type} = \%params;
}
$next->($c, %out_params);
};
1;
And the result:
[debug] Body Parameters are: .---------------------------+----------------------------. | Parameter | Value | +---------------------------+----------------------------+ | password | [FILTERED] | | user | some_user | '---------------------------+----------------------------'
Oh, and here’s a test, or at least pieces thereof:
package Adama::Test::Login::Logger;
use parent Catalyst::Log;
our $password = "somepass";
our $saw_password;
sub _send_to_log {
my ($self, @messages) = @_;
$saw_password = join("", @messages) =~ /$password/;
}
package Adama::Test::Login;
[much elided]
use Catalyst::Test 'Adama';
BEGIN {
Adama->log(Adama::Test::Login::Logger->new);
}
sub password_hidden :Tests(1) {
$Adama::Test::Login::Logger::saw_password = 0;
request(POST $LOGIN_URL, [
user => "some_user",
password => "somepass"
]);
ok(!$Adama::Test::Login::Logger::saw_password, "Password should not appear in debug logs");
}
I know it’s a bit ugly, but tests are kind of allowed to be a little bit ugly.
Leave a Reply