-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Multi auth methods per resource #990
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
base: master
Are you sure you want to change the base?
Changes from all commits
27a824f
dbf91cd
fe22f39
c997b77
ab5b843
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,8 @@ def show | |
|
||
if @resource && @resource.id | ||
# create client id | ||
# | ||
# REVIEW: Why isn't this using resource_class.create_new_auth_token? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This creates a new one without considering the previous tokens |
||
client_id = SecureRandom.urlsafe_base64(nil, false) | ||
token = SecureRandom.urlsafe_base64(nil, false) | ||
token_hash = BCrypt::Password.create(token) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,15 +27,14 @@ def redirect_callbacks | |
|
||
def omniauth_success | ||
get_resource_from_auth_hash | ||
create_token_info | ||
set_token_on_resource | ||
create_auth_params | ||
@auth_params = create_token_info | ||
|
||
if resource_class.devise_modules.include?(:confirmable) | ||
# don't send confirmation email!!! | ||
@resource.skip_confirmation! | ||
end | ||
|
||
# REVIEW: Shouldn't this be 'devise_mapping' instead of :user? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed |
||
sign_in(:user, @resource, store: false, bypass: false) | ||
|
||
@resource.save! | ||
|
@@ -157,30 +156,33 @@ def set_random_password | |
end | ||
|
||
def create_token_info | ||
# create token info | ||
@client_id = SecureRandom.urlsafe_base64(nil, false) | ||
@token = SecureRandom.urlsafe_base64(nil, false) | ||
@expiry = (Time.now + @resource.token_lifespan).to_i | ||
# These need to be instance variables so that we set the auth header info | ||
# correctly | ||
@provider_id = auth_hash['uid'] | ||
@provider = auth_hash['provider'] | ||
|
||
auth_values = @resource.create_new_auth_token(nil, @provider_id, @provider).symbolize_keys | ||
@client_id = auth_values['client'] | ||
@token = auth_values['access-token'] | ||
@expiry = auth_values['expiry'] | ||
@config = omniauth_params['config_name'] | ||
end | ||
|
||
def create_auth_params | ||
@auth_params = { | ||
auth_token: @token, | ||
client_id: @client_id, | ||
uid: @resource.uid, | ||
expiry: @expiry, | ||
config: @config | ||
} | ||
@auth_params.merge!(oauth_registration: true) if @oauth_registration | ||
@auth_params | ||
end | ||
|
||
def set_token_on_resource | ||
@resource.tokens[@client_id] = { | ||
token: BCrypt::Password.create(@token), | ||
expiry: @expiry | ||
} | ||
# The #create_new_auth_token values returned here have the token set as | ||
# the "access-token" value. Unfortunately, the previous implementation | ||
# would render this attribute out as "auth_token". Which is inconsistent | ||
# and wrong, but if people are using the body of the auth response | ||
# instead of the headers, they may see failures here. Not changing at the | ||
# moment as this would therefore be a breaking change. Same goes for | ||
# client_id/client. | ||
# | ||
# TODO: Fix this so that it consistently returns this in an | ||
# "access-token" field instead of an "auth_token". | ||
auth_values[:auth_token] = auth_values.delete(:"access-token") | ||
auth_values[:client_id] = auth_values.delete(:client) | ||
|
||
auth_values.merge!(config: @config) | ||
auth_values.merge!(oauth_registration: true) if @oauth_registration | ||
auth_values | ||
end | ||
|
||
def render_data(message, data) | ||
|
@@ -229,13 +231,15 @@ def fallback_render(text) | |
end | ||
|
||
def get_resource_from_auth_hash | ||
# find or create user by provider and provider uid | ||
@resource = resource_class.where({ | ||
uid: auth_hash['uid'], | ||
provider: auth_hash['provider'] | ||
}).first_or_initialize | ||
|
||
if @resource.new_record? | ||
@resource = resource_class.find_resource( | ||
auth_hash['uid'], | ||
auth_hash['provider'] | ||
) | ||
|
||
if @resource.nil? | ||
@resource = resource_class.new | ||
@resource.uid = auth_hash['uid'] if @resource.has_attribute?(:uid) | ||
@resource.provider = auth_hash['provider'] if @resource.has_attribute?(:provider) | ||
@oauth_registration = true | ||
set_random_password | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,8 @@ def create | |
|
||
else | ||
# email auth has been bypassed, authenticate user | ||
# | ||
# REVIEW: Shouldn't this be calling resource_class.create_new_auth_token? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should refactor |
||
@client_id = SecureRandom.urlsafe_base64(nil, false) | ||
@token = SecureRandom.urlsafe_base64(nil, false) | ||
|
||
|
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.
I guess it was previously logged with devise and doesn't have a token, maybe @lynndylanhurley can give some hint
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.
I tried just commenting the line out and re-running tests, and it led to a failing test that was added in PR #434. I repeated this on the
master
branch and it led to the same failing test.Upon closer inspection of PR #434, I'm not sure that the tests defined actually test the feature added (limiting concurrent devices/tokens). Furthermore, it looks like testing maximum concurrent tokens happens inside the block that tests the standard devise auth functionality rather than token auth.
Can anyone confirm or refute this?
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.
Thinking about this further, I'm having a hard time understanding a use case for this.
This block of code is only relevant if
DeviseTokenAuth.enable_standard_devise_support = true
, and if an existing user has been authenticated with warden/devise. Under these circumstances, it seems like not only is there no need to create a token, but the controller response should not contain any token auth related headers either.Does anyone know if a use case for returning token auth headers despite authenticating via warden/standard devise?
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.
@Evan-M please feel free to remove the tests for now or do what you need to do to move the PR forward!!
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.
Don't remove tests that should be working despite it's using single or multi auth providers. I don't know why this line, but if you can't find the reason, just remove the comment above
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.
Sorry @MaicolBen ....just trying to help @Evan-M move this PR forward as it's been open for a while and would be awesome to get in the project!
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.
@zachfeldman @MaicolBen: I am very reluctant to remove any tests!
However, I am trying to better understand the intent of these tests, and the implementation code that satisfies them. If warranted, I will re-write or re-factor some of these tests.
Admittedly, some of my questions/comments here are perhaps beyond the scope of this PR (allowing multiple auth methods per resource).
Currently, I've added 11 commits to my fork of this PR (
13 files changed, 102 insertions(+), 40 deletions(-)
, according togit diff --shortstat
). Additionally, there are prior the commits by @zachfeldman, @ram535ii, and others. Personally, I would prefer to provide shorter, and easier to understand (i.e. review) PRs.To this end, I plan on spending time this weekend to extract some of the commits from my fork into separate PRs. I think most of these separate PRs will focus on cleaning up confusing or redundant code, and ensuring that certain tests do in fact fully test what they intend to.
Perhaps most crucially, I want to ensure everything remains backwards compatible!
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.
@Evan-M I totally agree that this PR is huge and it's pretty hard to move forward with such a monolith....looking forward to seeing your work!