Commit f753c8b73b39f0e1b9f9b284333c11077b3495fd

Authored by Carlos Purificação
1 parent 0d2ac9fb

Implemented loging with captcha with mencache

lib/noosfero/api/captcha_session_store.rb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +class Noosfero::API::CaptchaSessionStore
  2 +
  3 + attr_accessor :data
  4 + attr_reader :private_token
  5 +
  6 + def self.create
  7 + key = SecureRandom.hex
  8 + store = Noosfero::API::CaptchaSessionStore.new(key)
  9 + Rails.cache.write(store.private_token, store, expires_in: 300)
  10 + return store
  11 + end
  12 +
  13 + def initialize(key)
  14 + @private_token = key
  15 + end
  16 +
  17 + def self.get(key)
  18 + Rails.cache.fetch(key)
  19 + end
  20 +
  21 + def store
  22 + Rails.cache.write(@private_token, self)
  23 + end
  24 +
  25 + def destroy
  26 + Rails.cache.delete(@private_token)
  27 + end
  28 +
  29 +
  30 +end
... ...
lib/noosfero/api/helpers.rb
... ... @@ -23,8 +23,7 @@ require 'grape'
23 23  
24 24 def current_tmp_user
25 25 private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s
26   - @current_tmp_user ||= User.find_by_private_token(private_token)
27   - @current_tmp_user = nil if !@current_tmp_user.nil? && @current_tmp_user.private_token_expired?
  26 + @current_tmp_user = Noosfero::API::CaptchaSessionStore.get(private_token)
28 27 @current_tmp_user
29 28 end
30 29  
... ... @@ -244,6 +243,13 @@ require 'grape'
244 243 unauthorized! unless current_user
245 244 end
246 245  
  246 + # Allows the anonymous captcha user authentication
  247 + # to pass the check. Used by the articles/vote to allow
  248 + # the vote without login
  249 + def authenticate_allow_captcha!
  250 + unauthorized! unless current_tmp_user || current_user
  251 + end
  252 +
247 253 # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash
248 254 # or a Bad Request error is invoked.
249 255 #
... ...
lib/noosfero/api/session.rb
... ... @@ -15,13 +15,9 @@ module Noosfero
15 15 # test_captcha will render_api_error! and exit in case of any problem
16 16 # this return is just to improve the clarity of the execution path
17 17 return unless test_captcha(remote_ip, params, environment)
18   -
19   - name = "tmp_user_#{remote_ip}"
20   - user = User.new(:name => name)
21   - user.generate_private_token!
22   -
23   - @current_tmp_user = user
24   - {:private_token => user.private_token}
  18 + ## Creates and caches a captcha session store
  19 + store = Noosfero::API::CaptchaSessionStore.create
  20 + { "private_token" => "#{store.private_token}" }
25 21 end
26 22  
27 23 # Login to get token
... ...
lib/noosfero/api/v1/articles.rb
... ... @@ -133,7 +133,8 @@ module Noosfero
133 133 named 'ArticleVote'
134 134 end
135 135 post ':id/vote' do
136   - authenticate!
  136 + ## The vote api should allow regular login or with captcha
  137 + authenticate_allow_captcha!
137 138 value = (params[:value] || 1).to_i
138 139 # FIXME verify allowed values
139 140 render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value)
... ...
test/unit/api/login_captcha_test.rb
... ... @@ -2,50 +2,72 @@ require File.dirname(__FILE__) + '/test_helper'
2 2  
3 3 class LoginCaptchaTest < ActiveSupport::TestCase
4 4  
5   - url = "/api/v1/login-captcha?"
6   -
7 5 def setup()
8   - environment = Environment.default
9   - environment.api_captcha_settings = {
  6 + @environment = Environment.default
  7 + @environment.api_captcha_settings = {
10 8 enabled: true,
11 9 provider: 'serpro',
12 10 serpro_client_id: '0000000000000000',
13 11 verify_uri: 'http://captcha.serpro.gov.br/validate',
14 12 }
15   - environment.save!
16   -
  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)
  20 + end
  21 +
  22 + should 'not perform a vote without authentication' do
  23 + article = create_article('Article 1')
  24 + params = {}
  25 + params[:value] = 1
  26 +
  27 + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
  28 + json = JSON.parse(last_response.body)
  29 + assert_equal 401, last_response.status
  30 + end
  31 +
  32 + should 'perform login from helpers' do
  33 + login_with_captcha
  34 + assert_not_nil @private_token
  35 + end
  36 +
  37 +
  38 + should 'perform a vote in an article identified by id' do
  39 + login_with_captcha
  40 + article = create_article('Article 1')
  41 + params[:value] = 1
  42 +
  43 + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}"
  44 + json = JSON.parse(last_response.body)
  45 +
  46 + assert_not_equal 401, last_response.status
  47 + assert_equal true, json['vote']
  48 + end
  49 +
  50 + should 'not follow any article' do
  51 + login_with_captcha
  52 + article = create_article('Article 1')
  53 + post "/api/v1/articles/#{article.id}/follow?#{params.to_query}"
  54 + json = JSON.parse(last_response.body)
  55 +
  56 + assert_equal 401, last_response.status
17 57 end
18 58  
19 59 should 'not generate private token when login without captcha' do
20 60 params = {}
21   - post "#{url}#{params.to_query}"
  61 + post "#{@url}#{params.to_query}"
22 62 json = JSON.parse(last_response.body)
23   - puts "JSon1: #{json}"
24 63 assert json["private_token"].blank?
25 64 end
26 65  
27 66 should 'generate private token when login with captcha' do
28   - #request = mock()
29   - stub_request(:post, "http://captcha.serpro.gov.br/validate").
30   - with(:body => "0000000000000000&4324343&4030320",
31   - :headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
32   - to_return(:status => 200, :body => "1", :headers => {})
33   -
34   - # Mock the user to check the private_token
35   - token = "private_token@1234"
36   - user = mock
37   - User.expects(:new).returns(user)
38   - user.expects(:generate_private_token!).returns(token)
39   - # To store the user session helpers.rb call the private_token method
40   - user.expects(:private_token).times(2).returns(token)
41   -
42   - params = {:txtToken_captcha_serpro_gov_br => '4324343', :captcha_text => '4030320'}
43   - post "#{url}#{params.to_query}"
44   - json = JSON.parse(last_response.body)
45   - puts "JSon2: #{json}"
46   - assert !json["private_token"].blank?
  67 + json = login_with_captcha
47 68 ret = json["private_token"]
48   - assert ret == token
  69 + assert !ret.blank?
  70 + assert ret == @private_token
49 71 end
50 72  
51 73 end
52 74 \ No newline at end of file
... ...
test/unit/api/test_helper.rb
... ... @@ -8,6 +8,38 @@ class ActiveSupport::TestCase
8 8 Noosfero::API::API
9 9 end
10 10  
  11 + def login_with_captcha
  12 + json = do_login_captcha_from_api
  13 + @private_token = json["private_token"]
  14 + @params = { "private_token" => @private_token}
  15 + json
  16 + end
  17 +
  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
  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)
  40 + json
  41 + end
  42 +
11 43 def login_api
12 44 @environment = Environment.default
13 45 @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => @environment)
... ...