diff options
author | azul <azul@leap.se> | 2014-05-26 10:08:27 +0200 |
---|---|---|
committer | azul <azul@leap.se> | 2014-05-26 10:08:27 +0200 |
commit | 1d0d61389011a8d0d169bc139590d90a6fbbac60 (patch) | |
tree | 9746836914f455889af9e24fdff36a1241ef4b24 | |
parent | df298887221cffc8cacc8965d73a0d7850118849 (diff) | |
parent | 5764daae090227bf4c5967900b708392c967be47 (diff) |
Merge pull request #163 from azul/feature/3398-save-hashed-token
hash token with sha512 against timing attacs #3398
-rw-r--r-- | app/controllers/controller_extension/token_authentication.rb | 4 | ||||
-rw-r--r-- | app/models/token.rb | 13 | ||||
-rw-r--r-- | test/functional/test_helpers_test.rb | 2 | ||||
-rw-r--r-- | test/functional/v1/sessions_controller_test.rb | 2 | ||||
-rw-r--r-- | test/integration/api/token_test.rb | 15 | ||||
-rw-r--r-- | test/support/auth_test_helper.rb | 5 | ||||
-rw-r--r-- | test/unit/token_test.rb | 23 |
7 files changed, 47 insertions, 17 deletions
diff --git a/app/controllers/controller_extension/token_authentication.rb b/app/controllers/controller_extension/token_authentication.rb index 6e0a6ce..b0ed624 100644 --- a/app/controllers/controller_extension/token_authentication.rb +++ b/app/controllers/controller_extension/token_authentication.rb @@ -2,8 +2,8 @@ module ControllerExtension::TokenAuthentication extend ActiveSupport::Concern def token - @token ||= authenticate_with_http_token do |token_id, options| - Token.find(token_id) + @token ||= authenticate_with_http_token do |token, options| + Token.find_by_token(token) end end diff --git a/app/models/token.rb b/app/models/token.rb index e759ee3..ff2ad12 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -1,3 +1,5 @@ +require 'digest/sha2' + class Token < CouchRest::Model::Base use_database :tokens @@ -11,10 +13,16 @@ class Token < CouchRest::Model::Base validates :user_id, presence: true + attr_accessor :token + design do view :by_last_seen_at end + def self.find_by_token(token) + self.find Digest::SHA512.hexdigest(token) + end + def self.expires_after APP_CONFIG[:auth] && APP_CONFIG[:auth][:token_expires_after] end @@ -31,7 +39,7 @@ class Token < CouchRest::Model::Base end def to_s - id + token end def authenticate @@ -65,7 +73,8 @@ class Token < CouchRest::Model::Base def initialize(*args) super if new_record? - self.id = SecureRandom.urlsafe_base64(32).gsub(/^_*/, '') + self.token = SecureRandom.urlsafe_base64(32).gsub(/^_*/, '') + self.id = Digest::SHA512.hexdigest(self.token) self.last_seen_at = Time.now end end diff --git a/test/functional/test_helpers_test.rb b/test/functional/test_helpers_test.rb index 845e516..ca85482 100644 --- a/test/functional/test_helpers_test.rb +++ b/test/functional/test_helpers_test.rb @@ -27,7 +27,7 @@ class TestHelpersTest < ActionController::TestCase def test_login_adds_token_header login token_present = @controller.authenticate_with_http_token do |token, options| - assert_equal @token.id, token + assert_equal @token.to_s, token end # authenticate_with_http_token just returns nil and does not # execute the block if there is no token. So we have to also diff --git a/test/functional/v1/sessions_controller_test.rb b/test/functional/v1/sessions_controller_test.rb index df0d681..8bb6acd 100644 --- a/test/functional/v1/sessions_controller_test.rb +++ b/test/functional/v1/sessions_controller_test.rb @@ -48,7 +48,7 @@ class V1::SessionsControllerTest < ActionController::TestCase assert_response :success assert json_response.keys.include?("id") assert json_response.keys.include?("token") - assert token = Token.find(json_response['token']) + assert token = Token.find_by_token(json_response['token']) assert_equal @user.id, token.user_id end diff --git a/test/integration/api/token_test.rb b/test/integration/api/token_test.rb new file mode 100644 index 0000000..ad3ac22 --- /dev/null +++ b/test/integration/api/token_test.rb @@ -0,0 +1,15 @@ +require 'test_helper' +require_relative 'srp_test' + +class TokenTest < SrpTest + + setup do + register_user + end + + test "stores token SHA512 encoded" do + authenticate + token = server_auth['token'] + assert Token.find(Digest::SHA512.hexdigest(token)) + end +end diff --git a/test/support/auth_test_helper.rb b/test/support/auth_test_helper.rb index e1961aa..38c2ea1 100644 --- a/test/support/auth_test_helper.rb +++ b/test/support/auth_test_helper.rb @@ -50,8 +50,9 @@ module AuthTestHelper protected def header_for_token_auth - @token = find_record(:token, :authenticate => @current_user) - ActionController::HttpAuthentication::Token.encode_credentials @token.id + @token = stub_record(:token, :authenticate => @current_user) + Token.stubs(:find_by_token).with(@token.token).returns(@token) + ActionController::HttpAuthentication::Token.encode_credentials @token.token end def expect_warden_logout diff --git a/test/unit/token_test.rb b/test/unit/token_test.rb index a3c6cf6..b143345 100644 --- a/test/unit/token_test.rb +++ b/test/unit/token_test.rb @@ -14,17 +14,22 @@ class ClientCertificateTest < ActiveSupport::TestCase assert_equal @user, sample.authenticate end - test "token id is secure" do + test "token is secure" do sample = Token.new(:user_id => @user.id) other = Token.new(:user_id => @user.id) - assert sample.id, - "id is set on initialization" - assert sample.id[0..10] != other.id[0..10], - "token id prefixes should not repeat" - assert /[g-zG-Z]/.match(sample.id), - "should use non hex chars in the token id" - assert sample.id.size > 16, - "token id should be more than 16 chars long" + assert sample.token, + "token is set on initialization" + assert sample.token[0..10] != other.token[0..10], + "token prefixes should not repeat" + assert /[g-zG-Z]/.match(sample.token), + "should use non hex chars in the token" + assert sample.token.size > 16, + "token should be more than 16 chars long" + end + + test "token id is hash of the token" do + sample = Token.new(:user_id => @user.id) + assert_equal Digest::SHA512.hexdigest(sample.token), sample.id end test "token checks for user" do |