| DBIx-PasswordIniFile documentation | Contained in the DBIx-PasswordIniFile distribution. |
$conn->connect( [\%attributes] ) (DEPRECATED)$conn->connectCached( [\%attributes] ) (DEPRECATED)$conn = DBIx::PasswordIniFile->getCachedConnection( 'path/to/file.ini' ) (DEPRECATED)$cache = DBIx::PasswordIniFile->getCache() (DEPRECATED)$dbh = $conn->dbh() (DEPRECATED)DBIx::PasswordIniFile - Manages DBI connections with password and other params stored in a .ini style file.
use DBIx::PasswordIniFile;
$conn = DBIx::PasswordIniFile->new(
-file => 'path/to/config.ini',
-section => 'database connection',
-key => 'encrypt and decrypt key',
-cipher => 'Blowfish'
);
$ary = $conn->getDBIConnectParams();
$dbh = DBI->connect( @$ary ) or die $DBI::errstr;
$encrypted_passw = $conn->changePassword('new_password');
$encrypted = $conn->encryptPassword( 'clear_password' );
$clear = $conn->decryptPassword( $encrypted );
# THIS METHODS ARE DEPRECATED:
$conn->connect( \%attributes ); # or
$conn->connect();
$conn->connectCached( \%attributes ); # or
$conn->connectCached();
$conn = DBIx::PasswordIniFile->getCachedConnection( 'path/to/file.ini' );
$hash_ref = DBIx::PasswordIniFile->getCache();
$dbh = $conn->dbh();
Manages DBI connection parameters stored in a .ini style configuration file
(really a Config::IniFiles config file), with password stored
encrypted.
This module allows you to store DBI connect params in a .ini style
configuration file, with password encrypted. .ini configuration files are
plain text files managed with Config::IniFiles module. Once written, there
is a command line utility called encpassw.pl that re-writes the .ini file,
encrypting the password. The same may be done programatically, calling
changePassword .
This module is similar to DBIx::Password. The differences are that
DBI connection parameters aren't stored as part of the module source
code (but in an external .ini style file), and that this module lets
you only one virtual user (i.e. one connection specification) per .ini file.
(THIS IS DEPRECATED) Like <DBIx::Password>, this is a subclass of DBI, so you
may call DBI function objects using DBIx::PasswordIniFile objects.
$conn = DBIx::PasswordIniFile->new( -file=>'path/to/file.ini', ...);
Creates a DBIx::PasswordIniFile object from DBI connection parameters
specified in path/to/file.ini file.
Apart from -file, other (optional) arguments are:
-section => 'db_config_section'
If specified, db_config_section is the section name of .ini file where
DBI connection parameters live.
If not specified, assumes that DBI connection parameters are in a section
with one of these names:
dsn
connect
connection
database
db
virtual user
If specified, but the section name doesn't exist, returns undef.
!! IMPORTANT !!
There are two alternate models for the content of this section, the old one
being deprecated. See CONTENT OF .ini file for more info about what
properties may be specified in this section of .ini file.
-key => 'encrypt_decrypt_key'
-cipher => 'name_of_encryption_module'
If specified, -key and -cipher are the encryption/decription key used for
storing/reading the password in .ini file, and the cipher algoritm.
If not specified -key, it's read from (with this order of preference):
$HOME/.DEFAULT_KEY file DBIx/DEFAULT_KEY file (from same dir as PasswordIniFile.pm)
(see FILES for more info)
Because default value for -key is stored in a file, it's a security break
to not specify this argument.
If not specified -cipher, it's assumed Blowfish. Note at least one
encription algorithm have to be installed (they live in Crypt:: spacename).
Usage sample:
use DBI;
use DBIx::PasswordIniFile;
$conn = new DBIx::PasswordIniFile( -file => 'my.ini');
$ary = $conn->getDBIConnectParams;
$dbh = DBI->connect( @$ary ) or die $DBI::errstr;
(DEPRECATED SAMPLE) Once a DBIx::PasswordIniFile object is created, use it
to call DBI object methods. For example:
use DBIx::PasswordIniFile;
$conn = new DBIx::PasswordIniFile( -file => 'my.ini');
$conn->connect();
...
$conn->disconnect(); # DBI object method.
$ary = $conn->getDBIConnectParams();
Reads from .ini configuration file specified in new and returns an array
ref like this:
[$dsn, $username, $password, $attributes]
Where $dsn, $username and $password are strings ($password in clear
form), and $attributes is a hash ref with connect attributes.
You may call a DBI connect as this:
$ary = $conn->getDBIConnectParams(); DBI->connect( @$ary );
!! IMPORTANT !!
This method assumes a different content in section of configuration .ini
file specified in new, than deprecated methods. See CONTENTS OF .ini file
for what parameters may be specified in .ini file.
$encrypted_passw = $conn->changePassword('new_clear_password')>
Replaces the encrypted password stored in .ini file with the result of
encrypting new_clear_password password (so, new_clear_password is the new
password in clear form).
Returns the new encrypted password saved in .ini file.
$encrypted_password = $conn->encryptPassword( $clear_password );
Encrypts a clear password.
$clear_password = $conn->decryptPassword( $encrypted_password );
Decrypts an encrypted password.
$conn->connect( [\%attributes] ) (DEPRECATED)Calls DBI->connect with values stored in .ini file specified in
new. \%attributes refers to last parameter of DBI->connect.
If specified, \%attributes take precedence over any conflicting stored in
..._attributes section of .ini file.
$conn->connectCached( [\%attributes] ) (DEPRECATED)Same as connect, but caches a copy of $conn object.
Cached objects may be retrieved with getCachedConnection.
$conn = DBIx::PasswordIniFile->getCachedConnection( 'path/to/file.ini' ) (DEPRECATED)Returns a valid DBIx::PasswordIniFile object corresponding to the .ini
file argument, if its connectCached was launched. Or returns undef if argument
doesn't correspond to a cached connection.
$cache = DBIx::PasswordIniFile->getCache() (DEPRECATED)Return a hash reference that is the cache. Keys are object references converted to
strings and values are valid DBIx::PasswordIniFile objects.
$dbh = $conn->dbh() (DEPRECATED)Returns the DBI database handler object (a DBIx::PasswordIniFile object
is a composition of a DBI object among others).
As explained in documentation of new, the file specified with -file is
a plain text file with a syntax compatible with Config::IniFiles.
Briefly (for more info see Config::IniFiles documentation):
parameter = value
[section] parameter1 = value1 parameter2 = value2 ...
[ and ]. # are comments and are ignored. Also, blank lines are
ignored. Use this with readability purposes.This module assumes the config file has a section whose name is specified as
$c = DBIx::PasswordIniFile( ... -section => $name ... );
Or one of the default section names if -section argument is not specified (if
more than one default section names exist and no -section is specified, the
first default section, in order of appearance, is assumed).
Well, this module assumes two alternate content models for this section, being DEPRECATED one of both:
dsn (mandatory) user (optional) pass (optional)
dsn, user and pass the fist three params passed to
DBI::connect .
$%attr param of DBI::connect) .
[database] dsn=dbi:mysql:database=suppliers;host=192.168.2.101;port=3306 user=ecastilla pass=52616e646f6d495621c18a03330fee46600ace348beeec28
encpassw.pl utility see perldoc
encpassw.pl for more info) driver (mandatory)
database
host
port
username
password
dsn
driver=ODBC then dsn, username and password are mandatory, and
all other parameters are ignored.
If driver isn't ODBC, then all parameters except database, username
and password are optional.
_attributes at the end.
For example, if your .ini file has a connect section, connection
attributes (if specified) are assumed to be in connection_attributes
section. If has a virtual user section, attributes are assumed to be
in virtual user_attributes, and so on.
..._attributes section aren't predefined and are used
as key/value pairs for \%attr argument when DBI connect method is
called.
.ini file, except
password value, that is stored encrypted using an encription
algorithm (default is Blowfish_PP).
.ini file content:
[db_config_section]
driver=mysql
database=suppliers
host=www.freesql.org
port=3306
username=ecastilla
password=52616e646f6d495621c18a03330fee46600ace348beeec28
[db_config_section_attributes]
PrintError=1
RaiseError=0
AutoCommit=1
[db_config_section]
driver=ODBC
dsn=FreeSQL
Other sections and properties of the .ini file are ignored, and do not
cause any undesired effect. This lets you use non dedicated .ini files
for storing DBI connection parameters.
When installed, a DEFAULT_KEY (NO dot prefixed) file is created at the same
directory of PasswordIniFile.pm. It stores a default key used when no -key
argument is specified in new .
You may override this file creating your own .DEFAULT_KEY (note dot prefixed)
file at your home directory.
In either case, content of this files is ONE line with a string used as key for
Crypt::CBC algorithm.
In .ini file, password is stored encrypted, and never in clear form. But note
that the mechanism is not completely secured because passwords are stored clear
in memory. A hack may do a memory dump and see the password.
Although with this limitation, I think the module is a good balance between security and simplicity.
Perl v5.8.6 or above has to be installed. If not, an error
Free to wrong pool XXX not YYY during global destruction
is displayed, and Perl crashes.
An encription module has to be installed. Default is to use
Crypt::Blowfish for encription and decription. If not installed Blowfish,
specify your preferred (without Crypt:: prefix).
There is an utility called encpassw.pl that takes a .ini file
and replaces the pass/password param value with its encrypted form.
Copyright 2005-2008 Enrique Castilla.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.
Enrique Castilla <mailto:ecastillacontreras@yahoo.es|ecastillacontreras@yahoo.es>.
| DBIx-PasswordIniFile documentation | Contained in the DBIx-PasswordIniFile distribution. |
package DBIx::PasswordIniFile; use strict; use vars qw($VERSION $AUTOLOAD); $VERSION = '2.00'; use DBI(); use Config::IniFiles; use Crypt::CBC; # Requires Crypt::Blowfish use File::HomeDir; my %connect_cache;
sub new { my $class = shift; my %args = @_; # Check that -file => $ini_file is a file return undef if !exists($args{-file}) || ! -e $args{-file}; my $config = new Config::IniFiles( -file => $args{-file} ); # If specified -section => $section, check it exists return undef if $args{-section} && ! $config->SectionExists($args{-section}); my $section = $args{-section}; if( ! $args{-section} ) { # Search section and assign to $section my @sections = grep( /^(dsn|connect|connection|database|db|virtual user)$/i, $config->Sections() ); return undef if !@sections; $section = $sections[0]; } return bless { config_ => $config, section_ => $section, key_ => ( $args{-key} || &get_default_key_ ), cipher_ => ( $args{-cipher} || 'Blowfish' ), dbh_ => 'dbh_' }, $class; }
sub getDBIConnectParams { my $self = shift; my( $config, $section) = ( $self->{config_}, $self->{section_} ); # This is what we return my($dsn, $username, $password, $attributes); $dsn = $config->val($section,'dsn'); $username = $config->val($section,'user'); $password = $config->val($section,'pass'); # Don«t decrypt if value of pass parameter was undef $password = $self->decryptPassword( $password ) if defined($password); # This method, unlike deprecated getConnectParams_ , assumes attributes # (%attr in DBI connect method) live in same file section. # All parameters distinct from 'dsn', 'user' and 'pass' are assumed to be # attributes. $attributes = {}; foreach my $attr ( $config->Parameters($section) ) { $attributes->{$attr} = $config->val($section,$attr) if $attr ne 'dsn' && $attr ne 'user' && $attr ne 'pass'; } return [ $dsn, $username, $password, $attributes ]; }
sub changePassword { my $self = shift; my $pass = shift; my $encrypt_pass = $self->encryptPassword($pass); my $param; my $cfg = $self->{config_}; $param = undef; $param = 'password' if $cfg->exists($self->{section_},'password') ; $param = 'pass' if $cfg->exists($self->{section_},'pass') ; if( ! $param ) { # Not specified. Guess pass or password # With old content model for .ini file, 'driver' param was mandatory, # and with new content model, this param does't exist. # So, existence or not existence of this param determines content model. # $param = ( $cfg->exists($self->{section_},'driver') ? 'password' : 'pass'); $cfg->newval( $self->{section_}, $param, $encrypt_pass ); } else { $cfg->setval($self->{section_}, $param, $encrypt_pass); } $cfg->RewriteConfig(); $cfg->ReadConfig(); return $encrypt_pass; }
sub encryptPassword { my $self = shift; my $pass = shift; my $cipher = Crypt::CBC->new( {'key' => $self->{key_}, 'cipher' => $self->{cipher_} }); $cipher->start('Encript'); my $ciphertext = $cipher->encrypt_hex($pass); $cipher->finish(); return $ciphertext; }
sub decryptPassword { my $self = shift; my $pass = shift; my $cipher = Crypt::CBC->new( {'key' => $self->{key_}, 'cipher' => $self->{cipher_} }); $cipher->start('Decript'); my $plaintext = $cipher->decrypt_hex($pass); $cipher->finish(); return $plaintext; }
sub connect { my($self,$options) = @_; my @params = @{$self->getConnectParams_()}; $params[-1] = { %{$params[-1]}, %$options } if $options && @params == 4; $params[3] = $options if $options && @params == 3; $self->{dbh_} = DBI->connect( @params ); return $self->{dbh_}; }
sub connectCached { my($self,$options) = @_; my @params = @{$self->getConnectParams_()}; $params[-1] = { %{$params[-1]}, %$options } if $options && @params == 4; $params[3] = $options if $options && @params == 3; $self->{dbh_} = DBI->connect( @params ); $connect_cache{$self} = $self; return $self->{dbh_}; }
sub getCachedConnection { my $class = shift; my $arg = shift; return undef if !$arg; foreach (keys %connect_cache) { my $cfg = $connect_cache{$_}->{config_}; return $connect_cache{$_} if $cfg->GetFileName() eq $arg; } }
sub getCache { my $class = shift; return \%connect_cache; }
sub dbh { my $self = shift; return $self->{dbh_}; } # =head2 get_default_key_ # # $def_key = &get_default_key_; # # Reads a default value for C<-key> argument from a .DEFAULT_KEY file in user's # home directory, or from a DEFAULT_KEY file in a @INC directory, the first one # found. In either case, reads the first line only. # # =cut sub get_default_key_ { my $dot_default_key_filepath = File::Spec->catfile(File::HomeDir->my_home, '.DEFAULT_KEY'); my $default_key_filepath = undef; unless( -e $dot_default_key_filepath ) { my $fp = undef; foreach my $path ( @INC ) { $fp = File::Spec->catfile($path, 'DBIx', 'DEFAULT_KEY'); if( -e $fp ) { $default_key_filepath = $fp; last; } } } else { $default_key_filepath = $dot_default_key_filepath; } die <<"DIE_MSG" if ! $default_key_filepath; !! Cannot find $dot_default_key_filepath nor a DEFAULT_KEY file in \@INC. Perhaps this last was accidentally removed. Create a new one with your default key, or specify -key in new. See perldoc __PACKAGE__ DIE_MSG open( my $fh, '<', $default_key_filepath ) or die $!; my $default_key = <$fh>; # one line only chomp($default_key); close $fh; return $default_key; } # =head2 getConnectParams_ (PRIVATE FUNCTION and DEPRECATED) # # $ary = $conn->getConnectParams_(); # # Reads from C<.ini> configuration file specified in C<new> and returns an array # ref like this: # # [$dsn, $username, $password, $attributes] # # Where C<$dsn>, C<$username> and C<$password> are strings (C<$password> in clear # form), and C<$attributes> is a hash ref with connect attributes. # # You may call a DBI connect as this: # # $ary = $conn->getConnectParams_(); # DBI->connect( @$ary ); # # =cut sub getConnectParams_ { my $self = shift; my( $config, $section) = ( $self->{config_}, $self->{section_} ); # This is what we return my($dsn, $username, $password, $attributes); my($driver,$database,$host,$port); $driver = $config->val($section,'driver'); $database = $config->val($section,'database'); $host = $config->val($section,'host'); $port = $config->val($section,'port'); $dsn = $config->val($section,'dsn'); $dsn = "DBI:ODBC:${dsn}" if uc($driver) eq 'ODBC'; $dsn = "DBI:${driver}:database=${database}" . ($host ? ";host=${host}" : '') . ($port ? ";port=${port}" : '') if uc($driver) ne 'ODBC'; $username = $config->val($section,'username'); $password = $config->val($section,'password'); # Don't decrypt if password parameter is undef $password = $self->decryptPassword( $password ) if $password; # attributes are supposed live in a file section called "$section_attributes" # (without double quotes). In this section, each parameter is an attribute # name. return [ $dsn, $username, $password ] if ! $config->SectionExists("${section}_attributes") ; $attributes = {}; if( $config->SectionExists("${section}_attributes") ) { foreach my $attr ( $config->Parameters("${section}_attributes") ) { $attributes->{$attr} = $config->val("${section}_attributes",$attr); } } return [ $dsn, $username, $password, $attributes ]; } ############################################################################## # AUTOLOAD function # Magically executes functions of DBI (DEPRECATED) ############################################################################## sub AUTOLOAD { my $self = shift; my @args = @_; my $name = $AUTOLOAD; $name =~ s/.*://; # Suppose we are calling a DBI function. return $self->{dbh_}->$name(@args) if ref($self); return DBI->$name(@args) if ! ref($self); } sub DESTROY { return; } 1; __END__