-
Notifications
You must be signed in to change notification settings - Fork 240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Digest tokens and cache #344
Open
philayres
wants to merge
21
commits into
gonzalo-bulnes:master
Choose a base branch
from
philayres:digest-tokens-and-cache
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
ffb03d9
Provide option to store the authentication token as a digest rather t…
philayres 7e127ef
Add cache of previous authentication to allow rapid re-authentication…
philayres 654b4b0
Add specs for cache providers and to test caching operates as expected
philayres 365aad8
Add missing expiration time to cache writes
philayres 31116f1
Ensure cache item invalidated if the token is set to nil
philayres 72a41ad
Remove byebug
philayres 4425d08
Ensure cache item invalidated if the token is set to nil
philayres 7b0f825
Ensure acts_as_token_authenticatable only applies changes to desired …
philayres b69956b
Merge commit '72a41ad8112457d5a61296d51980b892a732ef72' into divide-t…
philayres c766fcb
Merge commit '7b0f825d74fdb06fed415317f8dc90c332abbd47' into divide-t…
philayres bcaf00d
Ensure acts_as_token_authenticatable only applies changes to desired …
philayres fb1f96d
Squash commits
philayres 0feeb65
Upversion
philayres 1dcf3b0
Upversion
philayres 43af41a
Version update
philayres e005a56
Merge branch 'master' of https://github.com/gonzalo-bulnes/simple_tok…
philayres c9f0340
Merge branch 'master' into digest-tokens-and-cache
philayres 7ca0353
Merge branch 'master' of https://github.com/gonzalo-bulnes/simple_tok…
philayres 08d4294
Merge branch 'master' into digest-tokens-and-cache
philayres 7074edd
Merge branch 'master' of https://github.com/gonzalo-bulnes/simple_tok…
philayres 04db492
Upversion
philayres File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
lib/simple_token_authentication/_tmp_4df0ec6920c643bd_version.rb.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module SimpleTokenAuthentication | ||
VERSION = '1.17.2'.freeze | ||
end |
42 changes: 7 additions & 35 deletions
42
lib/simple_token_authentication/acts_as_token_authenticatable.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
require 'digest/sha2' | ||
require 'simple_token_authentication/cache' | ||
|
||
module SimpleTokenAuthentication | ||
module Cache | ||
|
||
# Cache previous authentications by a specific user record using a plain text token. | ||
# This allows rapid re-authentication for requests that store authentication tokens | ||
# as computationally expensive digests in the database. | ||
|
||
# Hash the plain text token with a strong, but computationally fast hashing function. | ||
# This aims to avoid snooping by other users of the cache, especially since many | ||
# caches do not require authentication by other system users. | ||
# This new digest does not provide the full protection from attack that the persisted token | ||
# BCrypt digest has, since it is not so computationally expensive, and therefore could be brute-forced. | ||
# Since this hash is only intended to be stored short-term in an in-memory cache | ||
# accessible by reasonably trusted system users, this compromise allows | ||
# rapid validation of previous authentications, with reasonable protection | ||
# against revealing tokens. | ||
|
||
# In order to reflect a session time out with cached authentications, the configuration provides | ||
# a `cache_expiration_time` setting. This is passed to the cache every time a new authentication | ||
# result is written. Enforcement of this time is expected to be performed by the cache. | ||
# Cache providers can also enforce this if the specific cache does not reliably enforce | ||
# this expiration time. | ||
|
||
def base_class | ||
raise NotImplementedError | ||
end | ||
|
||
# The current cache connection | ||
def connection= c | ||
@connection = c | ||
end | ||
|
||
def connection | ||
@connection | ||
end | ||
|
||
# Time to expire previous cached authentication results | ||
def expiration_time= e | ||
@expiration_time = e | ||
end | ||
|
||
def expiration_time | ||
@expiration_time | ||
end | ||
|
||
|
||
# Set a new cached authentication for this record, recording the | ||
# plain token, authentication status, and timestamp | ||
def set_new_auth record_id, plain_token, authenticated | ||
end | ||
|
||
# Get a new cached authentication for this record, recording the | ||
# plain token, authentication status, and timestamp | ||
def get_previous_auth record_id, plain_token | ||
end | ||
|
||
# Invalidate a previous cached authentication for this record | ||
def invalidate_auth record_id | ||
set_new_auth record_id, nil, false | ||
end | ||
|
||
# Generate a key to be used to identify the authentication for this user record | ||
def cache_record_key record_id | ||
{cache_record_type: 'simple_token_authentication auth record', record_id: record_id} | ||
end | ||
|
||
# Generate a stored value, containing the hashed token, current authentication status, | ||
# and a timestamp that can be used for additional TTL checking | ||
def cache_record_value token, record_id, authenticated | ||
{token: hash(token, record_id), authenticated: authenticated, updated_at: Time.now} | ||
end | ||
|
||
# Generate a digest using the user record id, the Devise configuration pepper and the | ||
# plain text token. | ||
def hash token, record_id | ||
Digest::SHA2.hexdigest("#{record_id}--#{SimpleTokenAuthentication.pepper}--#{token}") | ||
end | ||
|
||
# Simple check of the cache result to validate that the result was found, | ||
# the previous authentication was valid, and the authentication token has not changed | ||
def check_cache_result token, record_id, res | ||
res && res[:authenticated] == true && res[:token] == hash(token, record_id) | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
require 'dalli' | ||
require 'simple_token_authentication/cache' | ||
|
||
module SimpleTokenAuthentication | ||
module Caches | ||
class DalliProvider | ||
extend SimpleTokenAuthentication::Cache | ||
|
||
def self.base_class | ||
::Dalli | ||
end | ||
|
||
# Set a new cached authentication for this record, recording the | ||
# plain token, authentication status, and timestamp | ||
def self.set_new_auth record_id, plain_token, authenticated | ||
connection.set(cache_record_key(record_id), cache_record_value(plain_token, record_id, authenticated), expiration_time) | ||
end | ||
|
||
# Get a new cached authentication for this record, recording the | ||
# plain token, authentication status, and timestamp | ||
def self.get_previous_auth record_id, plain_token | ||
res = connection.get(cache_record_key(record_id)) | ||
check_cache_result plain_token, record_id, res | ||
end | ||
|
||
end | ||
end | ||
end |
28 changes: 28 additions & 0 deletions
28
lib/simple_token_authentication/caches/rails_cache_provider.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
require 'active_support/cache' | ||
require 'simple_token_authentication/cache' | ||
|
||
module SimpleTokenAuthentication | ||
module Caches | ||
class RailsCacheProvider | ||
extend SimpleTokenAuthentication::Cache | ||
|
||
def self.base_class | ||
::ActiveSupport::Cache::Store | ||
end | ||
|
||
# Set a new cached authentication for this record, recording the | ||
# plain token, authentication status, and timestamp | ||
def self.set_new_auth record_id, plain_token, authenticated | ||
connection.write(cache_record_key(record_id), cache_record_value(plain_token, record_id, authenticated), expires_in: expiration_time) | ||
end | ||
|
||
# Get a new cached authentication for this record, recording the | ||
# plain token, authentication status, and timestamp | ||
def self.get_previous_auth record_id, plain_token | ||
res = connection.fetch(cache_record_key(record_id)) | ||
check_cache_result plain_token, record_id, res | ||
end | ||
|
||
end | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it the other way around? I don't see other mentions of
sign_in_token
in this change set, so I assume it may be a typo? It may only be matter of flipping the condition around.Naming is hard, and that's true for config options as well, but the intent in the current implementation is to be read as "if the token is used as a sign in token" (
config.sign_in_token = true
) then sign in happens, which translates in a session being persisted. And if not (config.sign_in_token = false
), then there is no sign in and credentials must be provided with every request. (corresponding tests)