auth_query_spec.rb 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. # frozen_string_literal: true
  2. require_relative 'spec_helper'
  3. require_relative 'helpers/auth_query_helper'
  4. describe "Auth Query" do
  5. let(:configured_instances) {[5432, 10432]}
  6. let(:config_user) { { 'username' => 'sharding_user', 'password' => 'sharding_user' } }
  7. let(:pg_user) { { 'username' => 'sharding_user', 'password' => 'sharding_user' } }
  8. let(:processes) { Helpers::AuthQuery.single_shard_auth_query(pool_name: "sharded_db", pg_user: pg_user, config_user: config_user, extra_conf: config, wait_until_ready: wait_until_ready ) }
  9. let(:config) { {} }
  10. let(:wait_until_ready) { true }
  11. after do
  12. unless @failing_process
  13. processes.all_databases.map(&:reset)
  14. processes.pgcat.shutdown
  15. end
  16. @failing_process = false
  17. end
  18. context "when auth_query is not configured" do
  19. context 'and cleartext passwords are set' do
  20. it "uses local passwords" do
  21. conn = PG.connect(processes.pgcat.connection_string("sharded_db", config_user['username'], config_user['password']))
  22. expect(conn.async_exec("SELECT 1 + 2")).not_to be_nil
  23. end
  24. end
  25. context 'and cleartext passwords are not set' do
  26. let(:config_user) { { 'username' => 'sharding_user' } }
  27. it "does not start because it is not possible to authenticate" do
  28. @failing_process = true
  29. expect { processes.pgcat }.to raise_error(StandardError, /You have to specify a user password for every pool if auth_query is not specified/)
  30. end
  31. end
  32. end
  33. context 'when auth_query is configured' do
  34. context 'with global configuration' do
  35. around(:example) do |example|
  36. # Set up auth query
  37. Helpers::AuthQuery.set_up_auth_query_for_user(
  38. user: 'md5_auth_user',
  39. password: 'secret'
  40. );
  41. example.run
  42. # Drop auth query support
  43. Helpers::AuthQuery.tear_down_auth_query_for_user(
  44. user: 'md5_auth_user',
  45. password: 'secret'
  46. );
  47. end
  48. context 'with correct global parameters' do
  49. let(:config) { { 'general' => { 'auth_query' => "SELECT * FROM public.user_lookup('$1');", 'auth_query_user' => 'md5_auth_user', 'auth_query_password' => 'secret' } } }
  50. context 'and with cleartext passwords set' do
  51. it 'it uses local passwords' do
  52. conn = PG.connect(processes.pgcat.connection_string("sharded_db", pg_user['username'], pg_user['password']))
  53. expect(conn.exec("SELECT 1 + 2")).not_to be_nil
  54. end
  55. end
  56. context 'and with cleartext passwords not set' do
  57. let(:config_user) { { 'username' => 'sharding_user', 'password' => 'sharding_user' } }
  58. it 'it uses obtained passwords' do
  59. connection_string = processes.pgcat.connection_string("sharded_db", pg_user['username'], pg_user['password'])
  60. conn = PG.connect(connection_string)
  61. expect(conn.async_exec("SELECT 1 + 2")).not_to be_nil
  62. end
  63. it 'allows passwords to be changed without closing existing connections' do
  64. pgconn = PG.connect(processes.pgcat.connection_string("sharded_db", pg_user['username']))
  65. expect(pgconn.exec("SELECT 1 + 2")).not_to be_nil
  66. Helpers::AuthQuery.exec_in_instances(query: "ALTER USER #{pg_user['username']} WITH ENCRYPTED PASSWORD 'secret2';")
  67. expect(pgconn.exec("SELECT 1 + 4")).not_to be_nil
  68. Helpers::AuthQuery.exec_in_instances(query: "ALTER USER #{pg_user['username']} WITH ENCRYPTED PASSWORD '#{pg_user['password']}';")
  69. end
  70. it 'allows passwords to be changed and that new password is needed when reconnecting' do
  71. pgconn = PG.connect(processes.pgcat.connection_string("sharded_db", pg_user['username']))
  72. expect(pgconn.exec("SELECT 1 + 2")).not_to be_nil
  73. Helpers::AuthQuery.exec_in_instances(query: "ALTER USER #{pg_user['username']} WITH ENCRYPTED PASSWORD 'secret2';")
  74. newconn = PG.connect(processes.pgcat.connection_string("sharded_db", pg_user['username'], 'secret2'))
  75. expect(newconn.exec("SELECT 1 + 2")).not_to be_nil
  76. Helpers::AuthQuery.exec_in_instances(query: "ALTER USER #{pg_user['username']} WITH ENCRYPTED PASSWORD '#{pg_user['password']}';")
  77. end
  78. end
  79. end
  80. context 'with wrong parameters' do
  81. let(:config) { { 'general' => { 'auth_query' => 'SELECT 1', 'auth_query_user' => 'wrong_user', 'auth_query_password' => 'wrong' } } }
  82. context 'and with clear text passwords set' do
  83. it "it uses local passwords" do
  84. conn = PG.connect(processes.pgcat.connection_string("sharded_db", pg_user['username'], pg_user['password']))
  85. expect(conn.async_exec("SELECT 1 + 2")).not_to be_nil
  86. end
  87. end
  88. context 'and with cleartext passwords not set' do
  89. let(:config_user) { { 'username' => 'sharding_user' } }
  90. it "it fails to start as it cannot authenticate against servers" do
  91. @failing_process = true
  92. expect { PG.connect(processes.pgcat.connection_string("sharded_db", pg_user['username'], pg_user['password'])) }.to raise_error(StandardError, /Error trying to obtain password from auth_query/ )
  93. end
  94. context 'and we fix the issue and reload' do
  95. let(:wait_until_ready) { false }
  96. it 'fails in the beginning but starts working after reloading config' do
  97. connection_string = processes.pgcat.connection_string("sharded_db", pg_user['username'], pg_user['password'])
  98. while !(processes.pgcat.logs =~ /Waiting for clients/) do
  99. sleep 0.5
  100. end
  101. expect { PG.connect(connection_string)}.to raise_error(PG::ConnectionBad)
  102. expect(processes.pgcat.logs).to match(/Error trying to obtain password from auth_query/)
  103. current_config = processes.pgcat.current_config
  104. config = { 'general' => { 'auth_query' => "SELECT * FROM public.user_lookup('$1');", 'auth_query_user' => 'md5_auth_user', 'auth_query_password' => 'secret' } }
  105. processes.pgcat.update_config(current_config.deep_merge(config))
  106. processes.pgcat.reload_config
  107. conn = nil
  108. expect { conn = PG.connect(connection_string)}.not_to raise_error
  109. expect(conn.async_exec("SELECT 1 + 2")).not_to be_nil
  110. end
  111. end
  112. end
  113. end
  114. end
  115. context 'with per pool configuration' do
  116. around(:example) do |example|
  117. # Set up auth query
  118. Helpers::AuthQuery.set_up_auth_query_for_user(
  119. user: 'md5_auth_user',
  120. password: 'secret'
  121. );
  122. Helpers::AuthQuery.set_up_auth_query_for_user(
  123. user: 'md5_auth_user1',
  124. password: 'secret',
  125. database: 'shard1'
  126. );
  127. example.run
  128. # Tear down auth query
  129. Helpers::AuthQuery.tear_down_auth_query_for_user(
  130. user: 'md5_auth_user',
  131. password: 'secret'
  132. );
  133. Helpers::AuthQuery.tear_down_auth_query_for_user(
  134. user: 'md5_auth_user1',
  135. password: 'secret',
  136. database: 'shard1'
  137. );
  138. end
  139. context 'with correct parameters' do
  140. let(:processes) { Helpers::AuthQuery.two_pools_auth_query(pool_names: ["sharded_db0", "sharded_db1"], pg_user: pg_user, config_user: config_user, extra_conf: config ) }
  141. let(:config) {
  142. { 'pools' =>
  143. {
  144. 'sharded_db0' => {
  145. 'auth_query' => "SELECT * FROM public.user_lookup('$1');",
  146. 'auth_query_user' => 'md5_auth_user',
  147. 'auth_query_password' => 'secret'
  148. },
  149. 'sharded_db1' => {
  150. 'auth_query' => "SELECT * FROM public.user_lookup('$1');",
  151. 'auth_query_user' => 'md5_auth_user1',
  152. 'auth_query_password' => 'secret'
  153. },
  154. }
  155. }
  156. }
  157. context 'and with cleartext passwords set' do
  158. it 'it uses local passwords' do
  159. conn = PG.connect(processes.pgcat.connection_string("sharded_db0", pg_user['username'], pg_user['password']))
  160. expect(conn.exec("SELECT 1 + 2")).not_to be_nil
  161. conn = PG.connect(processes.pgcat.connection_string("sharded_db1", pg_user['username'], pg_user['password']))
  162. expect(conn.exec("SELECT 1 + 2")).not_to be_nil
  163. end
  164. end
  165. context 'and with cleartext passwords not set' do
  166. let(:config_user) { { 'username' => 'sharding_user' } }
  167. it 'it uses obtained passwords' do
  168. connection_string = processes.pgcat.connection_string("sharded_db0", pg_user['username'], pg_user['password'])
  169. conn = PG.connect(connection_string)
  170. expect(conn.async_exec("SELECT 1 + 2")).not_to be_nil
  171. connection_string = processes.pgcat.connection_string("sharded_db1", pg_user['username'], pg_user['password'])
  172. conn = PG.connect(connection_string)
  173. expect(conn.async_exec("SELECT 1 + 2")).not_to be_nil
  174. end
  175. end
  176. end
  177. end
  178. end
  179. end