Skip to content

Commit

Permalink
Enable configdb to be run on same server as database
Browse files Browse the repository at this point in the history
  • Loading branch information
abeverley committed Jan 10, 2025
1 parent 1db24f8 commit 56dafbc
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 67 deletions.
48 changes: 41 additions & 7 deletions bin/configdb.pl
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@
use FindBin;
use lib "$FindBin::Bin/../lib";

use Brass::Actions ();
use Brass::ConfigDB;
use Brass::Schema;
use Getopt::Long;
use YAML qw/LoadFile/;
use Term::ReadKey;

my ($server, $type, $action, $param, $use, %update, $namespace, $pass);
Expand All @@ -42,19 +45,39 @@
# Stop here when loaded by a test script
return 1 if caller();

# Assume this is running on the same server as the brass database if the web
# server directory exists
my $is_local = -d '/srv/Brass';

my $sshpass = $ENV{SSHPASS};
if (!defined $sshpass)
if (!$is_local && !defined $sshpass)
{
# Get passphrase of user's SSH key, do not echo
ReadMode ('noecho');
print "Please enter the passphrase:\n";
$sshpass = <STDIN>;
chomp $sshpass;
my $sshpass = _get_passphrase("Please enter the passphrase of the local SSH key:");
$ENV{SSHPASS} = $sshpass;
ReadMode ('normal');
}

my $cdb = Brass::ConfigDB->new;
my ($pwdpass, $schema);
if ($is_local && $type eq 'pwd')
{
# If we are running directly on the server, get passphrase to
# ecnrypt/decrypt passwords (this is kept locally in /.configdb if
# accessing the database remotely)
$pwdpass = _get_passphrase("Please enter the passphrase for password encyrption and decryption:");

# Get direct connection from database - not needed for running on remote
# server
my $config_file = '/srv/Brass/config.yml';
-f $config_file
or error __x"Unable to find config file {file}", file => $config_file;
my $config = LoadFile $config_file;
my $db_config = $config->{plugins}->{DBIC}->{default};
my @connect = ($db_config->{dsn}, $db_config->{user}, $db_config->{password}, $db_config->{options});

$schema = Brass::Schema->connect(@connect);
}

my $cdb = Brass::ConfigDB->new(is_local => $is_local, schema => $schema);

my $ret = $cdb->run(
server => $server,
Expand All @@ -66,6 +89,17 @@
use => $use,
update => \%update,
sshpass => $sshpass,
pwdpass => $pwdpass,
);

print "$ret\n";

sub _get_passphrase
{ my $prompt = shift;
ReadMode ('noecho');
print "$prompt\n";
$sshpass = <STDIN>;
chomp $sshpass;
ReadMode ('normal');
$sshpass;
}
68 changes: 8 additions & 60 deletions lib/Brass/API.pm
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ package Brass::API;
use strict; use warnings;

use Brass::Actions ();
use Brass::ConfigDB;
use Crypt::Blowfish;
use Crypt::CBC;
use Crypt::JWT qw(decode_jwt);
use Crypt::PK::ECC;
use Dancer2 appname => 'Brass';
Expand Down Expand Up @@ -79,10 +79,7 @@ hook before => sub {
var payload => $client;
};

sub randompw()
{ my $pwgen = CtrlO::Crypt::XkcdPassword->new;
$pwgen->xkcd( words => 3, digits => 2 );
}
my $cdb = Brass::ConfigDB->new(is_local => 1, schema => schema);

get 'api/pwd/' => sub {
my $user = var 'api_user'
Expand All @@ -93,63 +90,14 @@ get 'api/pwd/' => sub {
my $passphrase = var('payload')->{passphrase}
or error __"Need passphrase for retrieving and setting passwords";

my $server = query_parameters->get('server')
or error __"Please specify server";

my $action = query_parameters->get('action')
or error __"Need required action";

Brass::Actions::is_allowed_action($action)
or error __x"Invalid action: {action}", action => $action;

my $param = query_parameters->get('param');
!Brass::Actions::action_requires_pwd($action) || $param
or error __x"Please specify required username for {action} password",
action => $action;

my ($username) = $schema->resultset('Pw')->search({
'server.name' => $server,
'me.username' => $param,
'me.type' => $action,
},{
join => 'server',
});

my $cipher = Crypt::CBC->new(
-key => $passphrase,
-cipher => 'Blowfish'
my $pass = $cdb->run_pwd(
server => query_parameters->get('server'),
pass => query_parameters->get('pass'),
action => query_parameters->get('action'),
param => query_parameters->get('param'),
pwdpass => $passphrase,
);

my $pass = query_parameters->get('pass');
if (defined $pass) {
# check password is strong
my $pwcheck = Data::Password::Check->check({
password => $pass,
tests => [qw(length silly repeated)]
});
if ($pwcheck->has_errors) {
error __"Please use a secure password, provided password is not secure : " .
join(',', @{ $pwcheck->error_list });
}
}
if ($username) {
# update password if new one provided
if ($pass) {
my $pw = $cipher->encrypt($pass);
$username->pwencrypt($pw);
$username->update();
}
else {
$pass = $cipher->decrypt($username->pwencrypt);
}
}
else {
$pass //= randompw;
my $pw = $cipher->encrypt($pass);
my $s = $schema->resultset('Server')->find_or_create({ name => $server });
my $u = $schema->resultset('Pw')->create({ server_id => $s->id, username => $param, pwencrypt => $pw, type => $action });
$pass = $cipher->decrypt($u->pwencrypt);
}
content_type 'application/json';
encode_json({
"is_error" => 0,
Expand Down
98 changes: 98 additions & 0 deletions lib/Brass/ConfigDB.pm
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,37 @@ use CtrlO::Crypt::XkcdPassword;
use URI;
use URI::QueryParam;

has is_local => (
is => 'ro',
);

has schema => (
is => 'ro',
);

sub run
{ my ($self, %params) = @_;

return $self->_run_local(%params)
if $self->is_local;

$self->_run_remote(%params);
}

sub _run_local
{ my ($self, %params) = @_;

my $type = delete $params{type}
or error __"Please provide type of request with --type";

# XXX More types to be migrated
if ($type eq 'pwd')
{
$self->run_pwd(%params);
}
}

sub _run_remote
{ my ($self, %params) = @_;

my $server = $params{server};
Expand Down Expand Up @@ -159,6 +189,74 @@ sub run
}
}

sub run_pwd
{ my ($self, %params) = @_;

my $server = $params{server}
or error __"Please specify server";

my $action = $params{action}
or error __"Need required action";

Brass::Actions::is_allowed_action($action)
or error __x"Invalid action: {action}", action => $action;

my $param = $params{param};

!Brass::Actions::action_requires_pwd($action) || $param
or error __x"Please specify required username for {action} password",
action => $action;

my $pwdpass = $params{pwdpass}
or error __"Please provide the password encryption passphrase";

my ($username) = $self->schema->resultset('Pw')->search({
'server.name' => $server,
'me.username' => $param,
'me.type' => $action,
},{
join => 'server',
});

my $cipher = Crypt::CBC->new(
-key => $pwdpass,
-cipher => 'Blowfish'
);

my $pass = $params{pass};
if (defined $pass) {
# check password is strong
my $pwcheck = Data::Password::Check->check({
password => $pass,
tests => [qw(length silly repeated)]
});
if ($pwcheck->has_errors) {
error __"Please use a secure password, provided password is not secure : " .
join(',', @{ $pwcheck->error_list });
}
}
if ($username) {
# update password if new one provided
if ($pass) {
my $pw = $cipher->encrypt($pass);
$username->pwencrypt($pw);
$username->update();
}
else {
$pass = $cipher->decrypt($username->pwencrypt);
}
}
else {
$pass //= randompw();
my $pw = $cipher->encrypt($pass);
my $s = $self->schema->resultset('Server')->find_or_create({ name => $server });
my $u = $self->schema->resultset('Pw')->create({ server_id => $s->id, username => $param, pwencrypt => $pw, type => $action });
$pass = $cipher->decrypt($u->pwencrypt);
}

return $pass;
}

sub randompw()
{ my $pwgen = CtrlO::Crypt::XkcdPassword->new;
$pwgen->xkcd( words => 3, digits => 2 );
Expand Down

0 comments on commit 56dafbc

Please sign in to comment.