From: Ash Berlin Date: Thu, 9 Nov 2006 21:05:14 +0000 (+0000) Subject: First attempt at usable privilege granting (MySQL only currently) X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fabandoned%2Fmysql_grant_privileges_sketch;p=dbsrgits%2FDBIx-Class-Historic.git First attempt at usable privilege granting (MySQL only currently) --- diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index a0a34a8..cbcdadb 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -10,6 +10,7 @@ use SQL::Abstract::Limit; use DBIx::Class::Storage::DBI::Cursor; use DBIx::Class::Storage::Statistics; use IO::File; +use Carp::Clan qw/DBIx::Class/; __PACKAGE__->mk_group_accessors( 'simple' => @@ -1212,7 +1213,8 @@ sub deploy { next if($_ =~ /^COMMIT/m); next if $_ =~ /^\s+$/; # skip whitespace only $self->debugobj->query_start($_) if $self->debug; - $self->dbh->do($_) or warn "SQL was:\n $_"; # XXX exceptions? + eval {$self->dbh->do($_) or warn "SQL was:\n $_"}; # XXX exceptions? + if ($@) {warn "$@ while executing: $_\n";} $self->debugobj->query_end($_) if $self->debug; } } @@ -1252,6 +1254,98 @@ sub build_datetime_parser { return $type; } +=head2 pre_grant + +Prefrom any necesassry steps before preforming a GRANT operation. C<$args> +can be altered if needed. + +=over 4 + +=item Arguments: $args + +=item Return: true to continue processing grant operation + +=back + +=cut + +sub pre_grant { 1 }; + +=head2 post_grant + +Prefrom any necesassry steps after a GRANT command has been issued. For +example mysql will issue "FLUSH PRIVILEGES" + +=cut + +sub post_grant {}; + +=head2 grant_statements + +=cut + +sub grant_statements { + my ($self, $args) = @_; + + + my $entity = $args->{user} || $args->{group} or croak "Unable to get grant entity"; + + my $known_privileges = $self->known_privileges; + my @privs = grep { $known_privileges->{$_} } @{$args->{privileges}}; + + my $grant = "GRANT " . join(", ", @privs) . " ON $args->{object} TO $entity"; + + my ($user, $password) = @{$args}{qw/user password/}; + return $user && $password ? ($grant, $self->set_user_password($user, $password)) : ($grant); +} + +=head2 grant + +Grant privileges to an entity. This function takes a single hash ref +containing the following keys + +=over 4 + +=item user + +=item group + +These specify the entitiy to grant privileges to. If both are specified +C will be ignored. + +=item object + +The (database specific syntax) object to grant privileges on. For example this +could be a C for a MySQL, or a stored function name in Oracle +to grant execution rights upon. + +=item privileges + +An array ref of privileges to grant to entity on object. Currently this is +database specific, and any unknown privileges are silently ignored. + +=back + +=cut + +sub grant { + my ($self, $args) = @_; + + return unless $self->pre_grant($args); + + my @stmts = $self->grant_statements($args); + + foreach (@stmts) { + $self->dbh->do($_); + } + + $self->post_grant($args); +} + +sub current_schema { shift->throw_exception("DBI did not define current_schema"); } + +sub known_privileges { {} }; + sub DESTROY { my $self = shift; return if !$self->_dbh; diff --git a/lib/DBIx/Class/Storage/DBI/mysql.pm b/lib/DBIx/Class/Storage/DBI/mysql.pm index 8ecdfca..01d3e9f 100644 --- a/lib/DBIx/Class/Storage/DBI/mysql.pm +++ b/lib/DBIx/Class/Storage/DBI/mysql.pm @@ -16,6 +16,61 @@ sub sqlt_type { return 'MySQL'; } + +my @table_privileges = (qw/ + ALTER + CREATE + DELETE + FILE + INDEX + INSERT + SELECT + UPDATE + USAGE/, + 'CREATE TEMPORARY TABLE', + 'LOCK TABLES', + 'CREATE VIEW'); + +my @dba_privileges = ( + 'CREATE USER', + 'DROP', + 'EVENT', + 'PROCESS', + 'RELOAD', + 'REPLICATION CLIENT', + 'REPLICATION SLAVE', + 'SHUTDOWN', + 'SUPER', + 'GRANT OPTION', + 'ALL', + 'ALL PRIVILEGES'); + +my @stored_func_privileges = ( + 'ALTER ROUTINE', + 'CREATE ROUTINE', + 'EXECUTE', + 'TRIGGER'); + +sub known_privileges { + return { map { $_ => 1 } @table_privileges, @dba_privileges, @stored_func_privileges }; +} + +sub set_user_password { + my ($self, $user, $password) = @_; + + return "SET PASSWORD FOR $user = PASSWORD('$password')"; +} + +sub current_schema { + my ($self) = @_; + return $self->dbh->selectrow_arrayref("SELECT DATABASE()")->[0]; +} + +sub post_grant { + my ($self) = @_; + $self->dbh->do('FLUSH PRIVILEGES'); +} + 1; =head1 NAME