Skip to content
This repository was archived by the owner on Dec 20, 2018. It is now read-only.

Commit dd54a53

Browse files
Gargronkyori19
authored andcommitted
Add force_login option to OAuth authorize page (mastodon#8655)
* Add force_login option to OAuth authorize page For when a user needs to sign into an app from multiple accounts on the same server * When logging out from modal header, redirect back after re-login
1 parent 63bf604 commit dd54a53

7 files changed

Lines changed: 62 additions & 9 deletions

File tree

app/controllers/api/base_controller.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ def limit_param(default_limit)
5353
[params[:limit].to_i.abs, default_limit * 2].min
5454
end
5555

56-
def truthy_param?(key)
57-
ActiveModel::Type::Boolean.new.cast(params[key])
58-
end
59-
6056
def current_resource_owner
6157
@current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
6258
end

app/controllers/application_controller.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ def after_sign_out_path_for(_resource_or_scope)
5858

5959
protected
6060

61+
def truthy_param?(key)
62+
ActiveModel::Type::Boolean.new.cast(params[key])
63+
end
64+
6165
def forbidden
6266
respond_with_error(403)
6367
end

app/controllers/auth/sessions_controller.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ def create
2828
end
2929

3030
def destroy
31+
tmp_stored_location = stored_location_for(:user)
3132
super
3233
flash.delete(:notice)
34+
store_location_for(:user, tmp_stored_location) if continue_after?
3335
end
3436

3537
protected
@@ -124,8 +126,14 @@ def home_paths(resource)
124126
end
125127

126128
def clear_site_data
129+
return if continue_after?
130+
127131
# Should be '"*"' but that doen't work in Chrome (neither does '"executionContexts"')
128132
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data
129133
response.headers['Clear-Site-Data'] = '"cache", "cookies", "storage"'
130134
end
135+
136+
def continue_after?
137+
truthy_param?(:continue)
138+
end
131139
end

app/controllers/oauth/authorizations_controller.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,18 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
1313
def store_current_location
1414
store_location_for(:user, request.url)
1515
end
16+
17+
def render_success
18+
if skip_authorization? || (matching_token? && !truthy_param?('force_login'))
19+
redirect_or_render authorize_response
20+
elsif Doorkeeper.configuration.api_only
21+
render json: pre_auth
22+
else
23+
render :new
24+
end
25+
end
26+
27+
def truthy_param?(key)
28+
ActiveModel::Type::Boolean.new.cast(params[key])
29+
end
1630
end

app/views/layouts/modal.html.haml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
.name
99
= t 'users.signed_in_as'
1010
%span.username @#{current_account.local_username_and_domain}
11-
= link_to destroy_user_session_path, method: :delete, class: 'logout-link icon-button' do
11+
= link_to destroy_user_session_path(continue: true), method: :delete, class: 'logout-link icon-button' do
1212
= fa_icon 'sign-out'
1313

1414
.container-alt= yield

spec/controllers/auth/sessions_controller_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@
3030

3131
expect(response).to redirect_to(new_user_session_path)
3232
end
33+
34+
it 'does not delete redirect location with continue=true' do
35+
sign_in(user, scope: :user)
36+
controller.store_location_for(:user, '/authorize')
37+
delete :destroy, params: { continue: 'true' }
38+
expect(controller.stored_location_for(:user)).to eq '/authorize'
39+
end
3340
end
3441

3542
context 'with a suspended user' do

spec/controllers/oauth/authorizations_controller_spec.rb

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@
55
RSpec.describe Oauth::AuthorizationsController, type: :controller do
66
render_views
77

8-
let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/') }
8+
let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }
99

1010
describe 'GET #new' do
1111
subject do
12-
get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/' }
12+
get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read' }
1313
end
1414

1515
shared_examples 'stores location for user' do
1616
it 'stores location for user' do
1717
subject
18-
expect(controller.stored_location_for(:user)).to eq "/oauth/authorize?client_id=#{app.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code"
18+
expect(controller.stored_location_for(:user)).to eq "/oauth/authorize?client_id=#{app.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code&scope=read"
1919
end
2020
end
2121

2222
context 'when signed in' do
23+
let!(:user) { Fabricate(:user) }
24+
2325
before do
24-
sign_in Fabricate(:user), scope: :user
26+
sign_in user, scope: :user
2527
end
2628

2729
it 'returns http success' do
@@ -35,6 +37,28 @@
3537
end
3638

3739
include_examples 'stores location for user'
40+
41+
context 'when app is already authorized' do
42+
before do
43+
Doorkeeper::AccessToken.find_or_create_for(
44+
app,
45+
user.id,
46+
app.scopes,
47+
Doorkeeper.configuration.access_token_expires_in,
48+
Doorkeeper.configuration.refresh_token_enabled?
49+
)
50+
end
51+
52+
it 'redirects to callback' do
53+
subject
54+
expect(response).to redirect_to(/\A#{app.redirect_uri}/)
55+
end
56+
57+
it 'does not redirect to callback with force_login=true' do
58+
get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read', force_login: 'true' }
59+
expect(response.body).to match(/Authorize/)
60+
end
61+
end
3862
end
3963

4064
context 'when not signed in' do

0 commit comments

Comments
 (0)