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,9 +354,6 @@ class Environment < ActiveRecord::Base
354 354
355 settings_items :signup_welcome_screen_body, :type => String 355 settings_items :signup_welcome_screen_body, :type => String
356 356
357 - #Captcha settings  
358 - settings_items :api_captcha_settings, :default => {}  
359 -  
360 def has_custom_welcome_screen? 357 def has_custom_welcome_screen?
361 settings[:signup_welcome_screen_body].present? 358 settings[:signup_welcome_screen_body].present?
362 end 359 end
lib/noosfero/api/helpers.rb
@@ -434,99 +434,14 @@ require_relative '../../find_by_contents' @@ -434,99 +434,14 @@ require_relative '../../find_by_contents'
434 ########################################## 434 ##########################################
435 435
436 def test_captcha(remote_ip, params, environment) 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 end 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 end 445 end
531 446
532 end 447 end
lib/noosfero/plugin.rb
@@ -678,6 +678,11 @@ class Noosfero::Plugin @@ -678,6 +678,11 @@ class Noosfero::Plugin
678 nil 678 nil
679 end 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 # -> Adds additional blocks to profiles and environments. 686 # -> Adds additional blocks to profiles and environments.
682 # Your plugin must implements a class method called 'extra_blocks' 687 # Your plugin must implements a class method called 'extra_blocks'
683 # that returns a hash with the following syntax. 688 # that returns a hash with the following syntax.
plugins/recaptcha 0 → 160000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +Subproject commit 6767abef88d2b78c05b8c0edb67ca28e72348f6f
plugins/serpro_captcha 0 → 160000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +Subproject commit c6a155b608056d1cba387904e4ca34a5145a073f
test/unit/api/articles_test.rb
@@ -134,7 +134,7 @@ class ArticlesTest < ActiveSupport::TestCase @@ -134,7 +134,7 @@ class ArticlesTest < ActiveSupport::TestCase
134 ## Perform a vote twice in API should compute only one vote 134 ## Perform a vote twice in API should compute only one vote
135 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" 135 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
136 json = JSON.parse(last_response.body) 136 json = JSON.parse(last_response.body)
137 - 137 +
138 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" 138 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
139 json = JSON.parse(last_response.body) 139 json = JSON.parse(last_response.body)
140 140
@@ -168,7 +168,6 @@ class ArticlesTest < ActiveSupport::TestCase @@ -168,7 +168,6 @@ class ArticlesTest < ActiveSupport::TestCase
168 168
169 assert_not_equal 401, last_response.status 169 assert_not_equal 401, last_response.status
170 assert_equal true, json['vote'] 170 assert_equal true, json['vote']
171 -  
172 end 171 end
173 172
174 should 'not perform a vote in a archived article' do 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,74 +240,15 @@ class APIHelpersTest < ActiveSupport::TestCase
240 240
241 ###### Captcha tests ###### 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 ###### END Captcha tests ###### 253 ###### END Captcha tests ######
313 254
test/unit/api/login_captcha_test.rb
@@ -3,20 +3,8 @@ require File.dirname(__FILE__) + '/test_helper' @@ -3,20 +3,8 @@ require File.dirname(__FILE__) + '/test_helper'
3 class LoginCaptchaTest < ActiveSupport::TestCase 3 class LoginCaptchaTest < ActiveSupport::TestCase
4 4
5 def setup() 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 end 8 end
21 9
22 should 'not perform a vote without authentication' do 10 should 'not perform a vote without authentication' do
@@ -34,7 +22,6 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase @@ -34,7 +22,6 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
34 assert_not_nil @private_token 22 assert_not_nil @private_token
35 end 23 end
36 24
37 -  
38 should 'perform a vote in an article identified by id' do 25 should 'perform a vote in an article identified by id' do
39 login_with_captcha 26 login_with_captcha
40 article = create_article('Article 1') 27 article = create_article('Article 1')
@@ -42,7 +29,7 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase @@ -42,7 +29,7 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
42 29
43 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" 30 post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
44 json = JSON.parse(last_response.body) 31 json = JSON.parse(last_response.body)
45 - 32 +
46 assert_not_equal 401, last_response.status 33 assert_not_equal 401, last_response.status
47 assert_equal true, json['vote'] 34 assert_equal true, json['vote']
48 end 35 end
@@ -77,9 +64,11 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase @@ -77,9 +64,11 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
77 end 64 end
78 65
79 should 'not generate private token when login without captcha' do 66 should 'not generate private token when login without captcha' do
  67 + OutcomeCaptcha.outcome_captcha_test = false
80 params = {} 68 params = {}
81 post "#{@url}#{params.to_query}" 69 post "#{@url}#{params.to_query}"
82 json = JSON.parse(last_response.body) 70 json = JSON.parse(last_response.body)
  71 + assert_equal last_response.status, 403
83 assert json["private_token"].blank? 72 assert json["private_token"].blank?
84 end 73 end
85 74
@@ -90,4 +79,8 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase @@ -90,4 +79,8 @@ class LoginCaptchaTest &lt; ActiveSupport::TestCase
90 assert ret == @private_token 79 assert ret == @private_token
91 end 80 end
92 81
93 -end  
94 \ No newline at end of file 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,6 +4,7 @@ class SessionTest &lt; ActiveSupport::TestCase
4 4
5 def setup 5 def setup
6 login_api 6 login_api
  7 + OutcomeCaptcha.outcome_captcha_test = true
7 end 8 end
8 9
9 should 'generate private token when login' do 10 should 'generate private token when login' do
@@ -182,6 +183,14 @@ class SessionTest &lt; ActiveSupport::TestCase @@ -182,6 +183,14 @@ class SessionTest &lt; ActiveSupport::TestCase
182 assert_equal 404, last_response.status 183 assert_equal 404, last_response.status
183 end 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 should 'not return private token when the registered user is inactive' do 194 should 'not return private token when the registered user is inactive' do
186 params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" } 195 params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" }
187 post "/api/v1/register?#{params.to_query}" 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 class ActiveSupport::TestCase 22 class ActiveSupport::TestCase
4 23
5 include Rack::Test::Methods 24 include Rack::Test::Methods
  25 + include Noosfero::API::APIHelpers
6 26
7 def app 27 def app
8 Noosfero::API::API 28 Noosfero::API::API
@@ -15,31 +35,18 @@ class ActiveSupport::TestCase @@ -15,31 +35,18 @@ class ActiveSupport::TestCase
15 json 35 json
16 end 36 end
17 37
18 - ## Performs a login using the session.rb but mocking the  
19 - ## real HTTP request to validate the captcha.  
20 def do_login_captcha_from_api 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 json 41 json
41 end 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 def login_api 50 def login_api
44 @environment = Environment.default 51 @environment = Environment.default
45 @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => @environment) 52 @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => @environment)