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 @@ @@ -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,8 +23,7 @@ require 'grape'
23 23
24 def current_tmp_user 24 def current_tmp_user
25 private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s 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 @current_tmp_user 27 @current_tmp_user
29 end 28 end
30 29
@@ -244,6 +243,13 @@ require 'grape' @@ -244,6 +243,13 @@ require 'grape'
244 unauthorized! unless current_user 243 unauthorized! unless current_user
245 end 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 # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash 253 # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash
248 # or a Bad Request error is invoked. 254 # or a Bad Request error is invoked.
249 # 255 #
lib/noosfero/api/session.rb
@@ -15,13 +15,9 @@ module Noosfero @@ -15,13 +15,9 @@ module Noosfero
15 # test_captcha will render_api_error! and exit in case of any problem 15 # test_captcha will render_api_error! and exit in case of any problem
16 # this return is just to improve the clarity of the execution path 16 # this return is just to improve the clarity of the execution path
17 return unless test_captcha(remote_ip, params, environment) 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 end 21 end
26 22
27 # Login to get token 23 # Login to get token
lib/noosfero/api/v1/articles.rb
@@ -133,7 +133,8 @@ module Noosfero @@ -133,7 +133,8 @@ module Noosfero
133 named 'ArticleVote' 133 named 'ArticleVote'
134 end 134 end
135 post ':id/vote' do 135 post ':id/vote' do
136 - authenticate! 136 + ## The vote api should allow regular login or with captcha
  137 + authenticate_allow_captcha!
137 value = (params[:value] || 1).to_i 138 value = (params[:value] || 1).to_i
138 # FIXME verify allowed values 139 # FIXME verify allowed values
139 render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value) 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,50 +2,72 @@ require File.dirname(__FILE__) + '/test_helper'
2 2
3 class LoginCaptchaTest < ActiveSupport::TestCase 3 class LoginCaptchaTest < ActiveSupport::TestCase
4 4
5 - url = "/api/v1/login-captcha?"  
6 -  
7 def setup() 5 def setup()
8 - environment = Environment.default  
9 - environment.api_captcha_settings = { 6 + @environment = Environment.default
  7 + @environment.api_captcha_settings = {
10 enabled: true, 8 enabled: true,
11 provider: 'serpro', 9 provider: 'serpro',
12 serpro_client_id: '0000000000000000', 10 serpro_client_id: '0000000000000000',
13 verify_uri: 'http://captcha.serpro.gov.br/validate', 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 end 57 end
18 58
19 should 'not generate private token when login without captcha' do 59 should 'not generate private token when login without captcha' do
20 params = {} 60 params = {}
21 - post "#{url}#{params.to_query}" 61 + post "#{@url}#{params.to_query}"
22 json = JSON.parse(last_response.body) 62 json = JSON.parse(last_response.body)
23 - puts "JSon1: #{json}"  
24 assert json["private_token"].blank? 63 assert json["private_token"].blank?
25 end 64 end
26 65
27 should 'generate private token when login with captcha' do 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 ret = json["private_token"] 68 ret = json["private_token"]
48 - assert ret == token 69 + assert !ret.blank?
  70 + assert ret == @private_token
49 end 71 end
50 72
51 end 73 end
52 \ No newline at end of file 74 \ No newline at end of file
test/unit/api/test_helper.rb
@@ -8,6 +8,38 @@ class ActiveSupport::TestCase @@ -8,6 +8,38 @@ class ActiveSupport::TestCase
8 Noosfero::API::API 8 Noosfero::API::API
9 end 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 def login_api 43 def login_api
12 @environment = Environment.default 44 @environment = Environment.default
13 @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => @environment) 45 @user = User.create!(:login => 'testapi', :password => 'testapi', :password_confirmation => 'testapi', :email => 'test@test.org', :environment => @environment)