lib/posgra/driver.rb in posgra-0.1.9 vs lib/posgra/driver.rb in posgra-0.2.0
- old
+ new
@@ -3,10 +3,12 @@
include Posgra::Utils::Helper
DEFAULT_ACL_PRIVS = ENV['POSGRA_DEFAULT_ACL_PRIVS'] || 'arwdDxt'
DEFAULT_ACL = "{%s=#{DEFAULT_ACL_PRIVS}/%s}"
+ DEFAULT_DATABASE_ACL = "{%s=CTc/%s}"
+
DEFAULT_ACL_BY_KIND = {
'S' => '{%s=rwU/%s}'
}
PRIVILEGE_TYPES = {
@@ -19,10 +21,11 @@
't' => 'TRIGGER',
'U' => 'USAGE',
'R' => 'RULE',
'X' => 'EXECUTE',
'C' => 'CREATE',
+ 'c' => 'CONNECT',
'T' => 'TEMPORARY',
}
def initialize(client, options = {})
unless client.type_map_for_results.is_a?(PG::TypeMapAllStrings)
@@ -141,10 +144,22 @@
end
updated
end
+ def revoke_all_on_database(role, database)
+ sql = "REVOKE ALL ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}"
+ log(:info, sql, :color => :green)
+
+ unless @options[:dry_run]
+ exec(sql)
+ updated = true
+ end
+
+ updated
+ end
+
def grant(role, priv, options, schema, object)
updated = false
sql = "GRANT #{priv} ON #{@client.escape_identifier(schema)}.#{@client.escape_identifier(object)} TO #{@client.escape_identifier(role)}"
@@ -214,10 +229,83 @@
end
updated
end
+ def database_grant(role, priv, options, database)
+ updated = false
+
+ sql = "GRANT #{priv} ON DATABASE #{@client.escape_identifier(database)} TO #{@client.escape_identifier(role)}"
+
+ if options['is_grantable']
+ sql << ' WITH GRANT OPTION'
+ end
+
+ log(:info, sql, :color => :green)
+
+ unless @options[:dry_run]
+ exec(sql)
+ updated = true
+ end
+
+ updated
+ end
+
+ def update_database_grant_options(role, priv, options, database)
+ updated = false
+
+ if options.fetch('is_grantable')
+ updated = grant_database_grant_option(role, priv, database)
+ else
+ updated = roveke_database_grant_option(role, priv, database)
+ end
+
+ updated
+ end
+
+ def grant_database_grant_option(role, priv, database)
+ updated = false
+
+ sql = "GRANT #{priv} ON DATABASE #{@client.escape_identifier(database)} TO #{@client.escape_identifier(role)} WITH GRANT OPTION"
+ log(:info, sql, :color => :green)
+
+ unless @options[:dry_run]
+ exec(sql)
+ updated = true
+ end
+
+ updated
+ end
+
+ def roveke_database_grant_option(role, priv, database)
+ updated = false
+
+ sql = "REVOKE GRANT OPTION FOR #{priv} ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}"
+ log(:info, sql, :color => :green)
+
+ unless @options[:dry_run]
+ exec(sql)
+ updated = true
+ end
+
+ updated
+ end
+
+ def database_revoke(role, priv, database)
+ updated = false
+
+ sql = "REVOKE #{priv} ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}"
+ log(:info, sql, :color => :green)
+
+ unless @options[:dry_run]
+ exec(sql)
+ updated = true
+ end
+
+ updated
+ end
+
def describe_objects(schema)
rs = exec <<-SQL
SELECT
pg_class.relname,
pg_namespace.nspname
@@ -292,10 +380,11 @@
WHERE
pg_class.relkind NOT IN ('i')
SQL
grants_by_role = {}
+
rs.each do |row|
relname = row.fetch('relname')
nspname = row.fetch('nspname')
relacl = row.fetch('relacl')
usename = row.fetch('usename')
@@ -315,14 +404,55 @@
end
grants_by_role
end
+ def describe_databases
+ rs = exec <<-SQL
+ SELECT
+ pg_database.datname,
+ pg_database.datacl,
+ pg_user.usename
+ FROM
+ pg_database
+ INNER JOIN pg_user ON pg_database.datdba = pg_user.usesysid
+ SQL
+
+ database_grants_by_role = {}
+
+ rs.each do |row|
+ datname = row.fetch('datname')
+ datacl = row.fetch('datacl')
+ usename = row.fetch('usename')
+
+ next unless matched?(datname, @options[:include_database], @options[:exclude_database])
+
+ parse_database_aclitems(datacl, usename).each do |aclitem|
+ role = aclitem.fetch('grantee')
+ privs = aclitem.fetch('privileges')
+ next unless matched?(role, @options[:include_role], @options[:exclude_role])
+ database_grants_by_role[role] ||= {}
+ database_grants_by_role[role][datname] = privs
+ end
+ end
+
+ database_grants_by_role
+ end
+
private
def parse_aclitems(aclitems, owner, relkind)
aclitems_fmt = DEFAULT_ACL_BY_KIND.fetch(relkind, DEFAULT_ACL)
aclitems ||= aclitems_fmt % [owner, owner]
+ parse_aclitems0(aclitems)
+ end
+
+ def parse_database_aclitems(aclitems, owner)
+ aclitems ||= DEFAULT_DATABASE_ACL % [owner, owner]
+ parse_aclitems0(aclitems)
+ end
+
+ def parse_aclitems0(aclitems)
aclitems = aclitems[1..-2].split(',')
aclitems.map do |aclitem|
aclitem = unquote_aclitem(aclitem)
grantee, privileges_grantor = aclitem.split('=', 2)