Skip to content
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

Old password check before password update #317

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ The following routes are available for use by your client. These routes live rel
|:-----|:-------|:--------|
| / | POST | Email registration. Accepts **`email`**, **`password`**, and **`password_confirmation`** params. A verification email will be sent to the email address provided. Accepted params can be customized using the [`devise_parameter_sanitizer`](https://github.com/plataformatec/devise#strong-parameters) system. |
| / | DELETE | Account deletion. This route will destroy users identified by their **`uid`** and **`auth_token`** headers. |
| / | PUT | Account updates. This route will update an existing user's account settings. The default accepted params are **`password`** and **`password_confirmation`**, but this can be customized using the [`devise_parameter_sanitizer`](https://github.com/plataformatec/devise#strong-parameters) system. |
| / | PUT | Account updates. This route will update an existing user's account settings. The default accepted params are **`password`** and **`password_confirmation`**, but this can be customized using the [`devise_parameter_sanitizer`](https://github.com/plataformatec/devise#strong-parameters) system. If **`config.check_current_password_before_update`** is set to `:attributes` the **`current_password`** param is checked before any update, if it is set to `:password` the **`current_password`** param is checked only if the request updates user password. |
| /sign_in | POST | Email authentication. Accepts **`email`** and **`password`** as params. This route will return a JSON representation of the `User` model on successful login. |
| /sign_out | DELETE | Use this route to end the user's current session. This route will invalidate the user's authentication token. |
| /:provider | GET | Set this route as the destination for client authentication. Ideally this will happen in an external window or popup. [Read more](#omniauth-authentication). |
| /:provider/callback | GET/POST | Destination for the oauth2 provider's callback uri. `postMessage` events containing the authenticated user's data will be sent back to the main client window from this page. [Read more](#omniauth-authentication). |
| /validate_token | GET | Use this route to validate tokens on return visits to the client. Accepts **`uid`** and **`access-token`** as params. These values should correspond to the columns in your `User` table of the same names. |
| /password | POST | Use this route to send a password reset confirmation email to users that registered by email. Accepts **`email`** and **`redirect_url`** as params. The user matching the `email` param will be sent instructions on how to reset their password. `redirect_url` is the url to which the user will be redirected after visiting the link contained in the email. |
| /password | PUT | Use this route to change users' passwords. Accepts **`password`** and **`password_confirmation`** as params. This route is only valid for users that registered by email (OAuth2 users will receive an error). |
| /password | PUT | Use this route to change users' passwords. Accepts **`password`** and **`password_confirmation`** as params. This route is only valid for users that registered by email (OAuth2 users will receive an error). It also checks **`current_password`** if **`config.check_current_password_before_update`** is not set `false` (disabled by default). |
| /password/edit | GET | Verify user by password reset token. This route is the destination URL for password reset confirmation. This route must contain **`reset_password_token`** and **`redirect_url`** params. These values will be set automatically by the confirmation email that is generated by the password reset request. |

[Jump here](#usage-cont) for more usage information.
Expand Down Expand Up @@ -608,7 +608,7 @@ For example, the default behavior of the [`validate_token`](https://github.com/l
~~~ruby
# config/routes.rb
Rails.application.routes.draw do
...
...
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
token_validations: 'overrides/token_validations'
}
Expand Down
12 changes: 10 additions & 2 deletions app/controllers/devise_token_auth/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def update
}, status: 422
end

if @resource.update_attributes(password_resource_params)
if @resource.send(resource_update_method, password_resource_params)
yield if block_given?
return render json: {
success: true,
Expand All @@ -165,12 +165,20 @@ def update
end
end

def resource_update_method
if DeviseTokenAuth.check_current_password_before_update != false
"update_with_password"
else
"update_attributes"
end
end

def password_resource_params
params.permit(devise_parameter_sanitizer.for(:account_update))
end

def resource_params
params.permit(:email, :password, :password_confirmation, :reset_password_token)
params.permit(:email, :password, :password_confirmation, :current_password, :reset_password_token)
end

end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ def account_update_params
private

def resource_update_method
if account_update_params.has_key?(:current_password)
if DeviseTokenAuth.check_current_password_before_update == :attributes
"update_with_password"
elsif DeviseTokenAuth.check_current_password_before_update == :password and account_update_params.has_key?(:password)
"update_with_password"
elsif account_update_params.has_key?(:current_password)
"update_with_password"
else
"update_attributes"
Expand Down
18 changes: 10 additions & 8 deletions lib/devise_token_auth/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ class Engine < ::Rails::Engine
:omniauth_prefix,
:default_confirm_success_url,
:default_password_reset_url,
:redirect_whitelist
:redirect_whitelist,
:check_current_password_before_update

self.change_headers_on_each_request = true
self.token_lifespan = 2.weeks
self.batch_request_buffer_throttle = 5.seconds
self.omniauth_prefix = '/omniauth'
self.default_confirm_success_url = nil
self.default_password_reset_url = nil
self.redirect_whitelist = nil
self.change_headers_on_each_request = true
self.token_lifespan = 2.weeks
self.batch_request_buffer_throttle = 5.seconds
self.omniauth_prefix = '/omniauth'
self.default_confirm_success_url = nil
self.default_password_reset_url = nil
self.redirect_whitelist = nil
self.check_current_password_before_update = false

def self.setup(&block)
yield self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@
# example, using the default '/omniauth', the github oauth2 provider will
# redirect successful authentications to '/omniauth/github/callback'
#config.omniauth_prefix = "/omniauth"

# By defult sending current password is not needed for the password update.
# Uncomment to enforce current_password param to be checked before all
# attribute updates. Set it to :password if you want it to be checked only if
# password is updated.
# config.check_current_password_before_update = :attributes
end
50 changes: 50 additions & 0 deletions test/controllers/devise_token_auth/passwords_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,56 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase
end
end

describe "change password with current password required" do
before do
DeviseTokenAuth.check_current_password_before_update = :password
end

after do
DeviseTokenAuth.check_current_password_before_update = false
end

describe 'success' do
before do
@auth_headers = @resource.create_new_auth_token
request.headers.merge!(@auth_headers)
@new_password = Faker::Internet.password
@resource.update password: 'secret123', password_confirmation: 'secret123'

xhr :put, :update, {
password: @new_password,
password_confirmation: @new_password,
current_password: 'secret123'
}

@data = JSON.parse(response.body)
@resource.reload
end

test "request should be successful" do
assert_equal 200, response.status
end
end

describe 'current password mismatch error' do
before do
@auth_headers = @resource.create_new_auth_token
request.headers.merge!(@auth_headers)
@new_password = Faker::Internet.password

xhr :put, :update, {
password: @new_password,
password_confirmation: @new_password,
current_password: 'not_very_secret321'
}
end

test 'response should fail unauthorized' do
assert_equal 422, response.status
end
end
end

describe "change password" do
describe 'success' do
before do
Expand Down
Loading