Commit 8f098f7c6d32adc350a1d21419a86f93b89438fe

Authored by Evandro Junior
0 parents
Exists in master

Plugin initial commit

Gemfile 0 → 100644
  1 +++ a/Gemfile
... ... @@ -0,0 +1 @@
  1 +gem 'webmock'
... ...
README.md 0 → 100644
  1 +++ a/README.md
... ... @@ -0,0 +1,6 @@
  1 +Sample config values:
  2 +
  3 +verify_uri 'http://captcha.servicoscorporativos.serpro.gov.br/captchavalidar/1.0.0/validar'
  4 +serpro_client_id 'fdbcdc7a0b754ee7ae9d865fda740f17'
  5 +
  6 +See http://stdcs.supst.serpro/manual/html/#captcha/page/introducao.html for more details
... ...
controllers/serpro_captcha_plugin_admin_controller.rb 0 → 100644
  1 +++ a/controllers/serpro_captcha_plugin_admin_controller.rb
... ... @@ -0,0 +1,17 @@
  1 +class SerproCaptchaPluginAdminController < PluginAdminController
  2 +
  3 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  4 +
  5 + def index
  6 + end
  7 +
  8 + def update
  9 + if @environment.update_attributes(params[:environment])
  10 + session[:notice] = _('Captcha configuration updated successfully.')
  11 + else
  12 + session[:notice] = _('Captcha configuration could not be saved.')
  13 + end
  14 + render :action => 'index'
  15 + end
  16 +
  17 +end
... ...
lib/ext/environment.rb 0 → 100644
  1 +++ a/lib/ext/environment.rb
... ... @@ -0,0 +1,35 @@
  1 +require_dependency 'environment'
  2 +
  3 +class Environment
  4 +
  5 + #Captcha settings
  6 + settings_items :serpro_captcha_plugin, :type => ActiveSupport::HashWithIndifferentAccess, :default => {}
  7 +
  8 +# settings_items :verify_uri, :type => :string, :default => 'http://captcha.servicoscorporativos.serpro.gov.br/captchavalidar/1.0.0/validar'
  9 +# settings_items :serpro_client_id, :type => :string, :default => 'fdbcdc7a0b754ee7ae9d865fda740f17'
  10 +
  11 + attr_accessible :serpro_captcha_plugin_attributes, :serpro_captcha_verify_uri, :serpro_captcha_client_id
  12 +
  13 + def serpro_captcha_plugin_attributes
  14 + self.serpro_captcha_plugin || {}
  15 + end
  16 +
  17 + def serpro_captcha_verify_uri= verify_uri
  18 + self.serpro_captcha_plugin = {} if self.serpro_captcha_plugin.blank?
  19 + self.serpro_captcha_plugin['serpro_captcha_verify_uri'] = verify_uri
  20 + end
  21 +
  22 + def serpro_captcha_verify_uri
  23 + self.serpro_captcha_plugin['serpro_captcha_verify_uri']
  24 + end
  25 +
  26 + def serpro_captcha_client_id= client_id
  27 + self.serpro_captcha_plugin = {} if self.serpro_captcha_plugin.blank?
  28 + self.serpro_captcha_plugin['serpro_captcha_client_id'] = client_id
  29 + end
  30 +
  31 + def serpro_captcha_client_id
  32 + self.serpro_captcha_plugin['serpro_captcha_client_id']
  33 + end
  34 +
  35 +end
... ...
lib/serpro_captcha_plugin.rb 0 → 100644
  1 +++ a/lib/serpro_captcha_plugin.rb
... ... @@ -0,0 +1,20 @@
  1 +class SerproCaptchaPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + _('Serpro\'s captcha plugin')
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("Provides a plugin to Serpro's captcha infrastructure.")
  9 + end
  10 +
  11 + def self.api_mount_points
  12 + [SerproCaptchaPlugin::API ]
  13 + end
  14 +
  15 + def test_captcha(remote_ip, params, environment)
  16 + scv = SerproCaptchaVerification.new
  17 + return scv.verify_serpro_captcha(environment.serpro_captcha_client_id, params[:txtToken_captcha_serpro_gov_br], params[:captcha_text], environment.serpro_captcha_verify_uri)
  18 + end
  19 +
  20 +end
... ...
lib/serpro_captcha_verification.rb 0 → 100644
  1 +++ a/lib/serpro_captcha_verification.rb
... ... @@ -0,0 +1,31 @@
  1 +class SerproCaptchaVerification
  2 +
  3 + # return true or a hash with the error
  4 + # :user_message, :status, :log_message, :javascript_console_message
  5 + def verify_serpro_captcha(client_id, token, captcha_text, verify_uri)
  6 + msg_icve = _('Internal captcha validation error')
  7 + msg_esca = 'Environment serpro_captcha_plugin_attributes'
  8 + return hash_error(msg_icve, 500, nil, "#{msg_esca} verify_uri not defined") if verify_uri.nil?
  9 + return hash_error(msg_icve, 500, nil, "#{msg_esca} client_id not defined") if client_id.nil?
  10 + return hash_error(_("Error processing token validation"), 500, nil, _("Missing Serpro's Captcha token")) unless token
  11 + return hash_error(_('Captcha text has not been filled'), 403) unless captcha_text
  12 + uri = URI(verify_uri)
  13 + http = Net::HTTP.new(uri.host, uri.port)
  14 + request = Net::HTTP::Post.new(uri.path)
  15 + verify_string = "#{client_id}&#{token}&#{captcha_text}"
  16 + request.body = verify_string
  17 + body = http.request(request).body
  18 + return true if body == '1'
  19 + return hash_error(_("Internal captcha validation error"), 500, body, "Unable to reach Serpro's Captcha validation service") if body == "Activity timed out"
  20 + return hash_error(_("Wrong captcha text, please try again"), 403) if body == '0'
  21 + return hash_error(_("Serpro's captcha token not found"), 500) if body == '2'
  22 + return hash_error(_("No data sent to validation server or other serious problem"), 500) if body == -1
  23 + #Catches all errors at the end
  24 + return hash_error(_("Internal captcha validation error"), 500, nil, "Error validating Serpro's captcha service returned: #{body}")
  25 + end
  26 +
  27 + def hash_error(user_message, status, log_message=nil, javascript_console_message=nil)
  28 + {user_message: user_message, status: status, log_message: log_message, javascript_console_message: javascript_console_message}
  29 + end
  30 +
  31 +end
... ...
test/functional/account_controller_plugin_test.rb 0 → 100644
  1 +++ a/test/functional/account_controller_plugin_test.rb
... ... @@ -0,0 +1,18 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# Re-raise errors caught by the controller.
  4 +class AccountController; def rescue_action(e) raise e end; end
  5 +
  6 +class AccountControllerPluginTest < ActionController::TestCase
  7 +
  8 + def setup
  9 + @controller = AccountController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 +
  13 + @environment = Environment.default
  14 + @environment.enabled_plugins = ['SerproCaptchaPlugin']
  15 + @environment.save!
  16 + end
  17 +
  18 +end
... ...
test/test_helper.rb 0 → 100644
  1 +++ a/test/test_helper.rb
... ... @@ -0,0 +1,65 @@
  1 +require "#{Rails.root}/lib/noosfero/api/helpers"
  2 +
  3 +class ActiveSupport::TestCase
  4 +
  5 + include Rack::Test::Methods
  6 +
  7 + def app
  8 + Noosfero::API::API
  9 + end
  10 +
  11 + def pass_captcha(mocked_url, captcha_verification_body)
  12 + stub_request(:post, mocked_url).
  13 + with(:body => captcha_verification_body,
  14 + :headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
  15 + to_return(:status => 200, :body => "1", :headers => {'Content-Length' => 1})
  16 + end
  17 +
  18 + def fail_captcha_text(mocked_url, captcha_verification_body)
  19 + stub_request(:post, mocked_url).
  20 + with(:body => captcha_verification_body,
  21 + :headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
  22 + to_return(:status => 200, :body => "0", :headers => {'Content-Length' => 1})
  23 + end
  24 +
  25 + def login_with_captcha
  26 + json = do_login_captcha_from_api
  27 + @private_token = json["private_token"]
  28 + @params = { "private_token" => @private_token}
  29 + json
  30 + end
  31 +
  32 + ## Performs a login using the session.rb but mocking the
  33 + ## real HTTP request to validate the captcha.
  34 + def do_login_captcha_from_api
  35 + post "/api/v1/login-captcha"
  36 + json = JSON.parse(last_response.body)
  37 + json
  38 + end
  39 +
  40 + def login_api
  41 + @environment = Environment.default
  42 + @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => @environment)
  43 + @user.activate
  44 + @person = @user.person
  45 +
  46 + post "/api/v1/login?login=testapi&password=testapi"
  47 + json = JSON.parse(last_response.body)
  48 + @private_token = json["private_token"]
  49 + unless @private_token
  50 + @user.generate_private_token!
  51 + @private_token = @user.private_token
  52 + end
  53 +
  54 + @params = {:private_token => @private_token}
  55 + end
  56 + attr_accessor :private_token, :user, :person, :params, :environment
  57 +
  58 + private
  59 +
  60 + def json_response_ids(kind)
  61 + json = JSON.parse(last_response.body)
  62 + json[kind.to_s].map {|c| c['id']}
  63 + end
  64 +
  65 +end
... ...
test/unit/serpro_captcha_verification_test.rb 0 → 100644
  1 +++ a/test/unit/serpro_captcha_verification_test.rb
... ... @@ -0,0 +1,109 @@
  1 +require 'webmock'
  2 +include WebMock::API
  3 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  4 +require_relative '../test_helper'
  5 +
  6 +class SerproCaptchaVerificationTest < ActiveSupport::TestCase
  7 +
  8 + def setup
  9 + @environment = Environment.default
  10 + @environment.enabled_plugins = ['SerproCaptchaPlugin']
  11 + @environment.serpro_captcha_verify_uri="http://www.somecompany.com:443/validate"
  12 + @environment.serpro_captcha_client_id='323232'
  13 + @environment.save!
  14 + @captcha_token = "642646"
  15 + @captcha_text = "44641441"
  16 + @captcha_verification_body = "#{@environment.serpro_captcha_client_id}&#{@captcha_token}&#{@captcha_text}"
  17 + end
  18 +
  19 + def login_with_captcha
  20 + store = Noosfero::API::SessionStore.create("captcha")
  21 + ## Initialize the data for the session store
  22 + store.data = []
  23 + ## Put it back in cache
  24 + store.store
  25 + { "private_token" => "#{store.private_token}" }
  26 + end
  27 +
  28 + def create_article(name)
  29 + person = fast_create(Person, :environment_id => @environment.id)
  30 + fast_create(Article, :profile_id => person.id, :name => name)
  31 + end
  32 +
  33 + should 'register a user when there are no enabled captcha pluging' do
  34 + @environment.enabled_plugins = []
  35 + @environment.save!
  36 + Environment.default.enable('skip_new_user_email_confirmation')
  37 + params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" }
  38 + post "/api/v1/register?#{params.to_query}"
  39 + assert_equal 201, last_response.status
  40 + json = JSON.parse(last_response.body)
  41 + assert User['newuserapi'].activated?
  42 + assert json['user']['private_token'].present?
  43 + end
  44 +
  45 + should 'not register a user if captcha fails' do
  46 + fail_captcha_text @environment.serpro_captcha_verify_uri, @captcha_verification_body
  47 + Environment.default.enable('skip_new_user_email_confirmation')
  48 + params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com", :txtToken_captcha_serpro_gov_br => @captcha_token, :captcha_text => @captcha_text}
  49 + post "/api/v1/register?#{params.to_query}"
  50 + assert_equal 403, last_response.status
  51 + json = JSON.parse(last_response.body)
  52 + assert_equal json["message"], _("Wrong captcha text, please try again")
  53 + end
  54 +
  55 + should 'verify_serpro_captcha' do
  56 + pass_captcha @environment.serpro_captcha_verify_uri, @captcha_verification_body
  57 + scv = SerproCaptchaVerification.new
  58 + assert scv.verify_serpro_captcha(@environment.serpro_captcha_client_id, @captcha_token, @captcha_text, @environment.serpro_captcha_verify_uri)
  59 + end
  60 +
  61 + should 'fail captcha if user has not filled Serpro\' captcha text' do
  62 + pass_captcha @environment.serpro_captcha_verify_uri, @captcha_verification_body
  63 + scv = SerproCaptchaVerification.new
  64 + hash = scv.verify_serpro_captcha(@environment.serpro_captcha_client_id, @captcha_token, nil, @environment.serpro_captcha_verify_uri)
  65 + assert hash[:user_message], _('Captcha text has not been filled')
  66 + end
  67 +
  68 + should 'fail captcha if Serpro\' captcha token has not been sent' do
  69 + pass_captcha @environment.serpro_captcha_verify_uri, @captcha_verification_body
  70 + scv = SerproCaptchaVerification.new
  71 + hash = scv.verify_serpro_captcha(@environment.serpro_captcha_client_id, nil, @captcha_text, @environment.serpro_captcha_verify_uri)
  72 + assert hash[:javascript_console_message], _("Missing Serpro's Captcha token")
  73 + end
  74 +
  75 + should 'fail captcha text' do
  76 + fail_captcha_text @environment.serpro_captcha_verify_uri, @captcha_verification_body
  77 + scv = SerproCaptchaVerification.new
  78 + hash = scv.verify_serpro_captcha(@environment.serpro_captcha_client_id, nil, @captcha_text, @environment.serpro_captcha_verify_uri)
  79 + assert hash[:javascript_console_message], _("Wrong captcha text, please try again")
  80 + end
  81 +
  82 + should 'not perform a vote without authentication' do
  83 + article = create_article('Article 1')
  84 + params = {}
  85 + params[:value] = 1
  86 +
  87 + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
  88 + json = JSON.parse(last_response.body)
  89 + assert_equal 401, last_response.status
  90 + end
  91 +
  92 + should 'perform a vote on an article identified by id' do
  93 + pass_captcha @environment.serpro_captcha_verify_uri, @captcha_verification_body
  94 + params = {}
  95 + params[:txtToken_captcha_serpro_gov_br]= @captcha_token
  96 + params[:captcha_text]= @captcha_text
  97 + post "/api/v1/login-captcha?#{params.to_query}"
  98 + json = JSON.parse(last_response.body)
  99 + article = create_article('Article 1')
  100 + params = {}
  101 + params[:private_token] = json['private_token']
  102 + params[:value] = 1
  103 + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
  104 + json = JSON.parse(last_response.body)
  105 + assert_not_equal 401, last_response.status
  106 + assert_equal true, json['vote']
  107 + end
  108 +
  109 +end
... ...
views/serpro_captcha_plugin_admin/index.html.erb 0 → 100644
  1 +++ a/views/serpro_captcha_plugin_admin/index.html.erb
... ... @@ -0,0 +1,28 @@
  1 +<h1><%= _("Serpro's Captcha Management") %> </h1>
  2 +
  3 +<%= labelled_form_for(:environment, :url => {:action => 'update'}) do |f| %>
  4 +
  5 +<table>
  6 + <tr>
  7 + <th><%= c_('Configuration') %></th>
  8 + <th><%= _('Value') %></th>
  9 + </tr>
  10 + <tr>
  11 + <td><%= _('Verify URI') %></td>
  12 + <td><%= text_field :environment, :serpro_captcha_verify_uri %></td>
  13 + </tr>
  14 + <tr>
  15 + <td><%= _('Client Id') %></td>
  16 + <td><%= text_field :environment, :serpro_captcha_client_id %></td>
  17 + </tr>
  18 +</table>
  19 +
  20 +
  21 +<div>
  22 + <% button_bar do %>
  23 + <%= submit_button('save', c_('Save changes')) %>
  24 + <%= button :back, _('Back to plugins administration panel'), :controller => 'plugins' %>
  25 + <% end %>
  26 +</div>
  27 +
  28 +<% end %>
... ...