mirror of
https://github.com/inspec/inspec
synced 2024-11-10 15:14:23 +00:00
commit
7a68d58904
2 changed files with 104 additions and 56 deletions
|
@ -1,5 +1,4 @@
|
|||
require "inspec/resources/command"
|
||||
require "hashie/mash"
|
||||
require "inspec/utils/database_helpers"
|
||||
require "htmlentities"
|
||||
require "rexml/document"
|
||||
|
@ -21,8 +20,9 @@ module Inspec::Resources
|
|||
end
|
||||
EXAMPLE
|
||||
|
||||
attr_reader :user, :password, :host, :service, :as_os_user, :as_db_role
|
||||
# rubocop:disable Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity
|
||||
attr_reader :bin, :db_role, :host, :password, :port, :service,
|
||||
:su_user, :user
|
||||
|
||||
def initialize(opts = {})
|
||||
@user = opts[:user]
|
||||
@password = opts[:password] || opts[:pass]
|
||||
|
@ -30,60 +30,35 @@ module Inspec::Resources
|
|||
Inspec.deprecate(:oracledb_session_pass_option, "The oracledb_session `pass` option is deprecated. Please use `password`.")
|
||||
end
|
||||
|
||||
@bin = "sqlplus"
|
||||
@host = opts[:host] || "localhost"
|
||||
@port = opts[:port] || "1521"
|
||||
@service = opts[:service]
|
||||
|
||||
# connection as sysdba stuff
|
||||
return skip_resource "Option 'as_os_user' not available in Windows" if inspec.os.windows? && opts[:as_os_user]
|
||||
|
||||
@su_user = opts[:as_os_user]
|
||||
@db_role = opts[:as_db_role]
|
||||
|
||||
# we prefer sqlci although it is way slower than sqlplus, but it understands csv properly
|
||||
@sqlcl_bin = "sql" unless opts.key?(:sqlplus_bin) # don't use it if user specified sqlplus_bin option
|
||||
@sqlcl_bin = opts[:sqlcl_bin] || nil
|
||||
@sqlplus_bin = opts[:sqlplus_bin] || "sqlplus"
|
||||
|
||||
return fail_resource "Can't run Oracle checks without authentication" if @su_user.nil? && (@user.nil? || @password.nil?)
|
||||
return fail_resource "You must provide a service name for the session" if @service.nil?
|
||||
skip_resource "Option 'as_os_user' not available in Windows" if inspec.os.windows? && su_user
|
||||
fail_resource "Can't run Oracle checks without authentication" unless su_user && (user || password)
|
||||
fail_resource "You must provide a service name for the session" unless service
|
||||
end
|
||||
|
||||
def query(q)
|
||||
escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"')
|
||||
# escape tables with $
|
||||
escaped_query = escaped_query.gsub("$", '\\$')
|
||||
|
||||
p = nil
|
||||
# use sqlplus if sqlcl is not available
|
||||
def query(sql)
|
||||
if @sqlcl_bin && inspec.command(@sqlcl_bin).exist?
|
||||
bin = @sqlcl_bin
|
||||
opts = "set sqlformat csv\nSET FEEDBACK OFF"
|
||||
p = :parse_csv_result
|
||||
@bin = @sqlcl_bin
|
||||
format_options = "set sqlformat csv\nSET FEEDBACK OFF"
|
||||
parser = :parse_csv_result
|
||||
else
|
||||
bin = @sqlplus_bin
|
||||
opts = "SET MARKUP HTML ON\nSET PAGESIZE 32000\nSET FEEDBACK OFF"
|
||||
p = :parse_html_result
|
||||
@bin = "#{@sqlplus_bin} -S"
|
||||
format_options = "SET MARKUP HTML ON\nSET PAGESIZE 32000\nSET FEEDBACK OFF"
|
||||
parser = :parse_html_result
|
||||
end
|
||||
|
||||
query = verify_query(escaped_query)
|
||||
query += ";" unless query.end_with?(";")
|
||||
if @db_role.nil?
|
||||
command = %{#{bin} "#{@user}"/"#{@password}"@#{@host}:#{@port}/#{@service} <<EOC\n#{opts}\n#{query}\nEXIT\nEOC}
|
||||
elsif @su_user.nil?
|
||||
command = %{#{bin} "#{@user}"/"#{@password}"@#{@host}:#{@port}/#{@service} as #{@db_role} <<EOC\n#{opts}\n#{query}\nEXIT\nEOC}
|
||||
else
|
||||
command = %{su - #{@su_user} -c "env ORACLE_SID=#{@service} #{bin} / as #{@db_role} <<EOC\n#{opts}\n#{query}\nEXIT\nEOC"}
|
||||
end
|
||||
cmd = inspec.command(command)
|
||||
command = command_builder(format_options, sql)
|
||||
inspec_cmd = inspec.command(command)
|
||||
|
||||
out = cmd.stdout + "\n" + cmd.stderr
|
||||
if out.downcase =~ /^error/
|
||||
# TODO: we need to throw an exception here
|
||||
# change once https://github.com/chef/inspec/issues/1205 is in
|
||||
warn "Could not execute the sql query #{out}"
|
||||
DatabaseHelper::SQLQueryResult.new(cmd, Hashie::Mash.new({}))
|
||||
end
|
||||
DatabaseHelper::SQLQueryResult.new(cmd, send(p, cmd.stdout))
|
||||
DatabaseHelper::SQLQueryResult.new(inspec_cmd, send(parser,
|
||||
inspec_cmd.stdout))
|
||||
end
|
||||
|
||||
def to_s
|
||||
|
@ -92,9 +67,30 @@ module Inspec::Resources
|
|||
|
||||
private
|
||||
|
||||
# 3 commands
|
||||
# regular user password
|
||||
# using a db_role
|
||||
# su, using a db_role
|
||||
def command_builder(format_options, query)
|
||||
verified_query = verify_query(query)
|
||||
sql_prefix, sql_postfix = "", ""
|
||||
if inspec.os.windows?
|
||||
sql_prefix = %{@'\n#{format_options}\n#{verified_query}\nEXIT\n'@ | }
|
||||
else
|
||||
sql_postfix = %{ <<'EOC'\n#{format_options}\n#{verified_query}\nEXIT\nEOC}
|
||||
end
|
||||
|
||||
if @db_role.nil?
|
||||
%{#{sql_prefix}#{bin} "#{user}"/"#{password}"@#{host}:#{port}/#{@service}#{sql_postfix}}
|
||||
elsif @su_user.nil?
|
||||
%{#{sql_prefix}#{bin} "#{user}"/"#{password}"@#{host}:#{port}/#{@service} as #{@db_role}#{sql_postfix}}
|
||||
else
|
||||
%{su - #{@su_user} -c "env ORACLE_SID=#{@service} #{bin} / as #{@db_role}#{sql_postfix}}
|
||||
end
|
||||
end
|
||||
|
||||
def verify_query(query)
|
||||
# ensure we have a ; at the end
|
||||
query + ";" unless query.strip.end_with?(";")
|
||||
query += ";" unless query.strip.end_with?(";")
|
||||
query
|
||||
end
|
||||
|
||||
|
@ -115,7 +111,7 @@ module Inspec::Resources
|
|||
results
|
||||
end
|
||||
|
||||
def parse_html_result(stdout) # rubocop:disable Metrics/AbcSize
|
||||
def parse_html_result(stdout)
|
||||
result = stdout
|
||||
# make oracle html valid html by removing the p tag, it does not include a closing tag
|
||||
result = result.gsub("<p>", "").gsub("</p>", "").gsub("<br>", "")
|
||||
|
|
|
@ -3,18 +3,70 @@ require "inspec/resource"
|
|||
require "inspec/resources/oracledb_session"
|
||||
|
||||
describe "Inspec::Resources::OracledbSession" do
|
||||
it "verify oracledb_session configuration" do
|
||||
resource = load_resource("oracledb_session", user: "SYSTEM", password: "supersecurepass", host: "localhost", service: "ORCL.localdomain")
|
||||
_(resource.user).must_equal "SYSTEM"
|
||||
_(resource.password).must_equal "supersecurepass"
|
||||
_(resource.host).must_equal "localhost"
|
||||
_(resource.service).must_equal "ORCL.localdomain"
|
||||
it "sqlplus Linux" do
|
||||
resource = quick_resource(:oracledb_session, :linux, user: "USER", password: "password", host: "localhost", service: "ORCL", port: 1527, sqlplus_bin: "/bin/sqlplus") do |cmd|
|
||||
cmd.strip!
|
||||
case cmd
|
||||
when "/bin/sqlplus -S \"USER\"/\"password\"@localhost:1527/ORCL <<'EOC'\nSET MARKUP HTML ON\nSET PAGESIZE 32000\nSET FEEDBACK OFF\nSELECT NAME AS VALUE FROM v$database;\nEXIT\nEOC" then
|
||||
stdout_file "test/unit/mock/cmd/oracle-result"
|
||||
else
|
||||
raise cmd.inspect
|
||||
end
|
||||
end
|
||||
|
||||
it "run a SQL query" do
|
||||
resource = load_resource("oracledb_session", user: "SYSTEM", password: "supersecurepass", host: "127.0.0.1", service: "ORCL.localdomain", port: 1527)
|
||||
_(resource.resource_skipped?).must_equal false
|
||||
query = resource.query("SELECT NAME AS VALUE FROM v$database;")
|
||||
_(query.size).must_equal 1
|
||||
_(query.row(0).column("value").value).must_equal "ORCL"
|
||||
end
|
||||
|
||||
it "sqlplus Windows" do
|
||||
resource = quick_resource(:oracledb_session, :windows, user: "USER", password: "password", host: "localhost", service: "ORCL", port: 1527, sqlplus_bin: "C:/sqlplus.exe") do |cmd|
|
||||
cmd.strip!
|
||||
case cmd
|
||||
when "@'\nSET MARKUP HTML ON\nSET PAGESIZE 32000\nSET FEEDBACK OFF\nSELECT NAME AS VALUE FROM v$database;\nEXIT\n'@ | C:/sqlplus.exe -S \"USER\"/\"password\"@localhost:1527/ORCL" then
|
||||
stdout_file "test/unit/mock/cmd/oracle-result"
|
||||
else
|
||||
raise cmd.inspect
|
||||
end
|
||||
end
|
||||
|
||||
_(resource.resource_skipped?).must_equal false
|
||||
query = resource.query("SELECT NAME AS VALUE FROM v$database;")
|
||||
_(query.size).must_equal 1
|
||||
_(query.row(0).column("value").value).must_equal "ORCL"
|
||||
end
|
||||
|
||||
it "skipped when sqlplus Windows as_os_user" do
|
||||
resource = quick_resource(:oracledb_session, :windows, user: "USER", password: "password", host: "localhost", service: "ORCL", port: 1527, sqlplus_bin: "C:/sqlplus.exe", as_os_user: "Administrator")
|
||||
|
||||
_(resource.resource_skipped?).must_equal true
|
||||
_(resource.resource_exception_message).must_equal "Option 'as_os_user' not available in Windows"
|
||||
end
|
||||
|
||||
it "fails when no user, password, or su" do
|
||||
resource = quick_resource(:oracledb_session, :windows, host: "localhost", service: "ORCL", port: 1527, sqlplus_bin: "C:/sqlplus.exe")
|
||||
|
||||
_(resource.resource_failed?).must_equal true
|
||||
_(resource.resource_exception_message).must_equal "Can't run Oracle checks without authentication"
|
||||
end
|
||||
|
||||
it "fails when no service name is provided" do
|
||||
resource = quick_resource(:oracledb_session, :windows, user: "USER", password: "password", host: "localhost", port: 1527, sqlplus_bin: "C:/sqlplus.exe")
|
||||
|
||||
_(resource.resource_failed?).must_equal true
|
||||
_(resource.resource_exception_message).must_equal "You must provide a service name for the session"
|
||||
end
|
||||
|
||||
it "verify oracledb_session configuration" do
|
||||
resource = quick_resource(:oracledb_session, :linux, user: "USER", password: "password", host: "localhost", service: "ORCL", as_db_role: "dbrole", as_os_user: "osuser")
|
||||
_(resource.user).must_equal "USER"
|
||||
_(resource.password).must_equal "password"
|
||||
_(resource.host).must_equal "localhost"
|
||||
_(resource.port).must_equal "1521"
|
||||
_(resource.service).must_equal "ORCL"
|
||||
_(resource.db_role).must_equal "dbrole"
|
||||
_(resource.su_user).must_equal "osuser"
|
||||
_(resource.bin).must_equal "sqlplus"
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue