Commit a1b696f2d65abe71993ec1fc781926a3345a0d1e

Authored by Francisco Júnior
2 parents 792973f8 6639db52

Merge branch 'captcha_serpro_plugin' into staging

app/models/environment.rb
... ... @@ -354,9 +354,6 @@ class Environment < ActiveRecord::Base
354 354  
355 355 settings_items :signup_welcome_screen_body, :type => String
356 356  
357   - #Captcha settings
358   - settings_items :api_captcha_settings, :default => {}
359   -
360 357 def has_custom_welcome_screen?
361 358 settings[:signup_welcome_screen_body].present?
362 359 end
... ...
lib/noosfero/api/helpers.rb
... ... @@ -434,99 +434,14 @@ require_relative '../../find_by_contents'
434 434 ##########################################
435 435  
436 436 def test_captcha(remote_ip, params, environment)
437   - d = environment.api_captcha_settings
438   - return true unless d[:enabled] == true
439   - msg_icve = _('Internal captcha validation error')
440   - msg_eacs = 'Environment api_captcha_settings'
441   - s = 500
442   -
443   - if d[:provider] == 'google'
444   - return render_api_error!(msg_icve, s, nil, "#{msg_eacs} private_key not defined") if d[:private_key].nil?
445   - return render_api_error!(msg_icve, s, nil, "#{msg_eacs} version not defined") unless d[:version] == 1 || d[:version] == 2
446   - if d[:version] == 1
447   - d[:verify_uri] ||= 'https://www.google.com/recaptcha/api/verify'
448   - return verify_recaptcha_v1(remote_ip, d[:private_key], d[:verify_uri], params[:recaptcha_challenge_field], params[:recaptcha_response_field])
449   - end
450   - if d[:version] == 2
451   - d[:verify_uri] ||= 'https://www.google.com/recaptcha/api/siteverify'
452   - return verify_recaptcha_v2(remote_ip, d[:private_key], d[:verify_uri], params[:g_recaptcha_response])
453   - end
454   - end
455   - if d[:provider] == 'serpro'
456   - return render_api_error!(msg_icve, s, nil, "#{msg_eacs} verify_uri not defined") if d[:verify_uri].nil?
457   - return verify_serpro_captcha(d[:serpro_client_id], params[:txtToken_captcha_serpro_gov_br], params[:captcha_text], d[:verify_uri])
458   - end
459   - return render_api_error!(msg_icve, s, nil, "#{msg_eacs} provider not defined")
460   - end
461   -
462   - def verify_recaptcha_v1(remote_ip, private_key, api_recaptcha_verify_uri, recaptcha_challenge_field, recaptcha_response_field)
463   - if recaptcha_challenge_field == nil || recaptcha_response_field == nil
464   - return render_api_error!(_('Captcha validation error'), 500, nil, _('Missing captcha data'))
465   - end
466   -
467   - verify_hash = {
468   - "privatekey" => private_key,
469   - "remoteip" => remote_ip,
470   - "challenge" => recaptcha_challenge_field,
471   - "response" => recaptcha_response_field
472   - }
473   - uri = URI(api_recaptcha_verify_uri)
474   - https = Net::HTTP.new(uri.host, uri.port)
475   - https.use_ssl = true
476   - request = Net::HTTP::Post.new(uri.path)
477   - request.set_form_data(verify_hash)
478   - begin
479   - result = https.request(request).body.split("\n")
480   - rescue Exception => e
481   - return render_api_error!(_('Internal captcha validation error'), 500, nil, "Error validating Googles' recaptcha version 1: #{e.message}")
482   - end
483   - return true if result[0] == "true"
484   - return render_api_error!(_("Wrong captcha text, please try again"), 403, nil, "Error validating Googles' recaptcha version 1: #{result[1]}") if result[1] == "incorrect-captcha-sol"
485   - #Catches all errors at the end
486   - return render_api_error!(_("Internal recaptcha validation error"), 500, nil, "Error validating Googles' recaptcha version 1: #{result[1]}")
487   - end
488   -
489   - def verify_recaptcha_v2(remote_ip, private_key, api_recaptcha_verify_uri, g_recaptcha_response)
490   - return render_api_error!(_('Captcha validation error'), 500, nil, _('Missing captcha data')) if g_recaptcha_response == nil
491   - verify_hash = {
492   - "secret" => private_key,
493   - "remoteip" => remote_ip,
494   - "response" => g_recaptcha_response
495   - }
496   - uri = URI(api_recaptcha_verify_uri)
497   - https = Net::HTTP.new(uri.host, uri.port)
498   - https.use_ssl = true
499   - request = Net::HTTP::Post.new(uri.path)
500   - request.set_form_data(verify_hash)
501   - begin
502   - body = https.request(request).body
503   - rescue Exception => e
504   - return render_api_error!(_('Internal captcha validation error'), 500, nil, "recaptcha error: #{e.message}")
505   - end
506   - captcha_result = JSON.parse(body)
507   - captcha_result["success"] ? true : captcha_result
508   - end
509   -
510   - def verify_serpro_captcha(client_id, token, captcha_text, verify_uri)
511   - return render_api_error!(_("Error processing token validation"), 500, nil, "Missing Serpro's Captcha token") unless token
512   - return render_api_error!(_('Captcha text has not been filled'), 403) unless captcha_text
513   - uri = URI(verify_uri)
514   - http = Net::HTTP.new(uri.host, uri.port)
515   - request = Net::HTTP::Post.new(uri.path)
516   - verify_string = "#{client_id}&#{token}&#{captcha_text}"
517   - request.body = verify_string
518   - begin
519   - body = http.request(request).body
520   - rescue Exception => e
521   - return render_api_error!(_('Internal captcha validation error'), 500, nil, "Serpro captcha error: #{e.message}")
  437 + captcha_plugin_enabled = @plugins.dispatch(:test_captcha, remote_ip, params, environment).map {|p| p if ! ( p===nil ) }
  438 + return true if captcha_plugin_enabled.size == 0
  439 + if captcha_plugin_enabled.size > 1
  440 + return render_api_error!(_("Error processing Captcha"), 500, nil, "More than one captcha plugin enabled")
522 441 end
523   - return true if body == '1'
524   - return render_api_error!(_("Internal captcha validation error"), 500, body, "Unable to reach Serpro's Captcha validation service") if body == "Activity timed out"
525   - return render_api_error!(_("Wrong captcha text, please try again"), 403) if body == 0
526   - return render_api_error!(_("Serpro's captcha token not found"), 500) if body == 2
527   - return render_api_error!(_("No data sent to validation server or other serious problem"), 500) if body == -1
528   - #Catches all errors at the end
529   - return render_api_error!(_("Internal captcha validation error"), 500, nil, "Error validating Serpro's captcha #{body}")
  442 + test_result = captcha_plugin_enabled[0]
  443 + return true if test_result === true
  444 + render_api_error!(test_result[:user_message], test_result[:status], test_result[:log_message], test_result[:javascript_console_message])
530 445 end
531 446  
532 447 end
... ...
lib/noosfero/plugin.rb
... ... @@ -678,6 +678,11 @@ class Noosfero::Plugin
678 678 nil
679 679 end
680 680  
  681 + #By default will return nil that will mean not implented by the plugin
  682 + def test_captcha(*args)
  683 + nil
  684 + end
  685 +
681 686 # -> Adds additional blocks to profiles and environments.
682 687 # Your plugin must implements a class method called 'extra_blocks'
683 688 # that returns a hash with the following syntax.
... ...
plugins/recaptcha 0 → 160000
... ... @@ -0,0 +1 @@
  1 +Subproject commit 6767abef88d2b78c05b8c0edb67ca28e72348f6f
... ...
plugins/serpro_captcha 0 → 160000
... ... @@ -0,0 +1 @@
  1 +Subproject commit c6a155b608056d1cba387904e4ca34a5145a073f
... ...
test/unit/api/articles_test.rb
... ... @@ -134,7 +134,7 @@ class ArticlesTest < ActiveSupport::TestCase
134 134 ## Perform a vote twice in API should compute only one vote
135 135 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
136 136 json = JSON.parse(last_response.body)
137   -
  137 +
138 138 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
139 139 json = JSON.parse(last_response.body)
140 140  
... ... @@ -168,7 +168,6 @@ class ArticlesTest < ActiveSupport::TestCase
168 168  
169 169 assert_not_equal 401, last_response.status
170 170 assert_equal true, json['vote']
171   -
172 171 end
173 172  
174 173 should 'not perform a vote in a archived article' do
... ...
test/unit/api/helpers_test.rb
... ... @@ -240,74 +240,15 @@ class APIHelpersTest < ActiveSupport::TestCase
240 240  
241 241 ###### Captcha tests ######
242 242  
243   -should 'do not test captcha when there are no settings' do
244   - environment = Environment.new
245   - assert test_captcha("127.0.0.1", {}, environment)
246   -end
247   -
248   -should 'do not test captcha when captcha is disabled on settings' do
249   - environment = Environment.new
250   - environment.api_captcha_settings = {
251   - enabled: false,
252   - }
253   - assert test_captcha("127.0.0.1", {}, environment)
254   -end
255   -
256   -should 'fail display recaptcha v1' do
257   - environment = Environment.new
258   - environment.api_captcha_settings = {
259   - enabled: true,
260   - provider: 'google',
261   - version: 1,
262   - private_key: '6LdsWAcTAAAAAB6maB_HalVyCc4asDAxPxloIMvY',
263   - public_key: '6LdsWAcTAAAAAChTUUD6yu9fCDhdIZzNd7F53zf-',
264   - verify_uri: 'https://www.google.com/recaptcha/api/verify',
265   - }
266   - r = test_captcha('127.0.0.1', params, environment)
267   - assert_equal(_("Missing captcha data"), r[0][:javascript_console_message])
268   -end
269   -
270   -should 'fail display recaptcha v2' do
271   - environment = Environment.new
272   - environment.api_captcha_settings = {
273   - enabled: true,
274   - provider: 'google',
275   - version: 2,
276   - private_key: '6LdsWAcTAAAAAB6maB_HalVyCc4asDAxPxloIMvY',
277   - public_key: '6LdsWAcTAAAAAChTUUD6yu9fCDhdIZzNd7F53zf-',
278   - verify_uri: 'https://www.google.com/recaptcha/api/siteverify',
279   - }
280   - r = test_captcha('127.0.0.1', params, environment)
281   - assert_equal(_("Missing captcha data"), r[0][:javascript_console_message])
282   -end
283   -
284   -should 'verify if user filled Serpro\' captcha text' do
285   - environment = Environment.new
286   - environment.api_captcha_settings = {
287   - enabled: true,
288   - provider: 'serpro',
289   - serpro_client_id: '0000000000000000',
290   - verify_uri: 'http://localhost/api/verify',
291   - }
292   - params = {}
293   - params[:txtToken_captcha_serpro_gov_br] = '4324343'
294   - assert_equal(_('Captcha text has not been filled'), test_captcha('127.0.0.1', params, environment)[0]['message'])
295   -end
296   -
297   -should 'verify if Serpro\' captcha token has been sent' do
298   - environment = Environment.new
299   - environment.api_captcha_settings = {
300   - enabled: true,
301   - provider: 'serpro',
302   - serpro_client_id: '0000000000000000',
303   - verify_uri: 'http://localhost/api/verify',
304   - }
305   - params = {}
306   - params[:captcha_text] = '4324343'
307   - r = test_captcha('127.0.0.1', params, environment)
308   - assert_equal(_("Missing Serpro's Captcha token"), r[0][:javascript_console_message])
309   -end
310   -
  243 + def plugins
  244 + environment = Environment.default
  245 + Noosfero::Plugin::Manager.new(environment, self)
  246 + end
  247 +
  248 + should 'do not test captcha when there is no captcha plugin enabled' do
  249 + environment = Environment.new
  250 + assert test_captcha("127.0.0.1", {}, environment)
  251 + end
311 252  
312 253 ###### END Captcha tests ######
313 254  
... ...
test/unit/api/login_captcha_test.rb
... ... @@ -3,20 +3,8 @@ require File.dirname(__FILE__) + '/test_helper'
3 3 class LoginCaptchaTest < ActiveSupport::TestCase
4 4  
5 5 def setup()
6   - @environment = Environment.default
7   - @environment.api_captcha_settings = {
8   - enabled: true,
9   - provider: 'serpro',
10   - serpro_client_id: '0000000000000000',
11   - verify_uri: 'http://captcha.serpro.gov.br/validate',
12   - }
13   - @environment.save!
14   - @url = "/api/v1/login-captcha?"
15   - end
16   -
17   - def create_article(name)
18   - person = fast_create(Person, :environment_id => @environment.id)
19   - fast_create(Article, :profile_id => person.id, :name => name)
  6 + @url = "/api/v1/login-captcha"
  7 + OutcomeCaptcha.outcome_captcha_test = true
20 8 end
21 9  
22 10 should 'not perform a vote without authentication' do
... ... @@ -34,7 +22,6 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
34 22 assert_not_nil @private_token
35 23 end
36 24  
37   -
38 25 should 'perform a vote in an article identified by id' do
39 26 login_with_captcha
40 27 article = create_article('Article 1')
... ... @@ -42,7 +29,7 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
42 29  
43 30 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
44 31 json = JSON.parse(last_response.body)
45   -
  32 +
46 33 assert_not_equal 401, last_response.status
47 34 assert_equal true, json['vote']
48 35 end
... ... @@ -77,9 +64,11 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
77 64 end
78 65  
79 66 should 'not generate private token when login without captcha' do
  67 + OutcomeCaptcha.outcome_captcha_test = false
80 68 params = {}
81 69 post "#{@url}#{params.to_query}"
82 70 json = JSON.parse(last_response.body)
  71 + assert_equal last_response.status, 403
83 72 assert json["private_token"].blank?
84 73 end
85 74  
... ... @@ -90,4 +79,8 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
90 79 assert ret == @private_token
91 80 end
92 81  
93   -end
94 82 \ No newline at end of file
  83 + should 'do login captcha from api' do
  84 + do_login_captcha_from_api
  85 + end
  86 +
  87 +end
... ...
test/unit/api/session_test.rb
... ... @@ -4,6 +4,7 @@ class SessionTest &lt; ActiveSupport::TestCase
4 4  
5 5 def setup
6 6 login_api
  7 + OutcomeCaptcha.outcome_captcha_test = true
7 8 end
8 9  
9 10 should 'generate private token when login' do
... ... @@ -182,6 +183,14 @@ class SessionTest &lt; ActiveSupport::TestCase
182 183 assert_equal 404, last_response.status
183 184 end
184 185  
  186 + should 'do not register a user if captcha fails' do
  187 + OutcomeCaptcha.outcome_captcha_test = false
  188 + Environment.default.enable('skip_new_user_email_confirmation')
  189 + params = {:login => "newuserapi_ewa ", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" }
  190 + post "/api/v1/register?#{params.to_query}"
  191 + assert_equal 403, last_response.status
  192 + end
  193 +
185 194 should 'not return private token when the registered user is inactive' do
186 195 params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" }
187 196 post "/api/v1/register?#{params.to_query}"
... ...
test/unit/api/test_helper.rb
1   -require_relative '../../test_helper'
  1 +require File.dirname(__FILE__) + '/../../test_helper'
  2 +require File.join(Rails.root, '/lib/noosfero/api/helpers.rb')
  3 +
  4 +class OutcomeCaptcha
  5 + class << self
  6 + attr_accessor :outcome_captcha_test
  7 + end
  8 + @outcome_captcha_test = true
  9 +end
  10 +
  11 +module Noosfero
  12 + module API
  13 + module APIHelpers
  14 + def test_captcha(*args)
  15 + return true if OutcomeCaptcha.outcome_captcha_test
  16 + render_api_error!("Error testing captcha", 403)
  17 + end
  18 + end
  19 + end
  20 +end
2 21  
3 22 class ActiveSupport::TestCase
4 23  
5 24 include Rack::Test::Methods
  25 + include Noosfero::API::APIHelpers
6 26  
7 27 def app
8 28 Noosfero::API::API
... ... @@ -15,31 +35,18 @@ class ActiveSupport::TestCase
15 35 json
16 36 end
17 37  
18   - ## Performs a login using the session.rb but mocking the
19   - ## real HTTP request to validate the captcha.
20 38 def do_login_captcha_from_api
21   - # Request mocking
22   - #Net::HTTP::Post Mock
23   - request = mock
24   - #Net::HTTP Mock
25   - http = mock
26   - uri = URI(environment.api_captcha_settings[:verify_uri])
27   - Net::HTTP.expects(:new).with(uri.host, uri.port).returns(http)
28   - Net::HTTP::Post.expects(:new).with(uri.path).returns(request)
29   -
30   - # Captcha required codes
31   - request.stubs(:body=).with("0000000000000000&4324343&4030320")
32   - http.stubs(:request).with(request).returns(http)
33   -
34   - # Captcha validation success !!
35   - http.stubs(:body).returns("1")
36   -
37   - params = {:txtToken_captcha_serpro_gov_br => '4324343', :captcha_text => '4030320'}
38   - post "#{@url}#{params.to_query}"
39   - json = JSON.parse(last_response.body)
  39 + post "/api/v1/login-captcha"
  40 + json = JSON.parse(last_response.body)
40 41 json
41 42 end
42 43  
  44 + def create_article(name)
  45 + @environment = Environment.default
  46 + person = fast_create(Person, :environment_id => @environment.id)
  47 + fast_create(Article, :profile_id => person.id, :name => name)
  48 + end
  49 +
43 50 def login_api
44 51 @environment = Environment.default
45 52 @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => @environment)
... ...