Skip to content

Commit c9a122f

Browse files
committed
use new rack-oauth2 rails support feature
1 parent 3997233 commit c9a122f

File tree

8 files changed

+114
-42
lines changed

8 files changed

+114
-42
lines changed

Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,5 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
4848

4949
# NOTE: added by nov
5050
gem 'tpitale-constant_cache', require: 'constant_cache'
51+
gem 'rack-oauth2', '>= 1.3.1'
5152
gem 'openid_connect'
+26-35
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,45 @@
11
class AuthorizationsController < ApplicationController
2+
include Concerns::ConnectEndpoint
3+
4+
before_action :require_oauth_request
5+
before_action :require_response_type_code
6+
before_action :require_client
7+
before_action :require_authentication
8+
29
def new
310
end
411

512
def create
6-
authorization.save!
7-
separator = if current_client.redirect_uri.include?('?')
8-
'&'
13+
if params[:commit] == 'approve'
14+
authorization = current_account.authorizations.create(
15+
client: @client,
16+
nonce: oauth_request.nonce
17+
)
18+
authorization.scopes << requested_scopes
19+
oauth_response.code = authorization.code
20+
oauth_response.redirect_uri = @redirect_uri
21+
oauth_response.approve!
22+
redirect_to oauth_response.location
923
else
10-
'?'
24+
oauth_request.access_denied!
1125
end
12-
redirect_to [current_client.redirect_uri, {code: authorization.code, state: accepted_params[:state]}.to_query].join(separator)
1326
end
1427

1528
private
1629

17-
def authorization
18-
unless @authorization
19-
@authorization = current_account.authorizations.build(
20-
client: current_client,
21-
nonce: accepted_params[:nonce]
22-
)
23-
@authorization.scopes << requested_scopes
24-
end
25-
@authorization
26-
end
27-
helper_method :authorization
28-
29-
def accepted_params
30-
required_params = [:client_id, :response_type, :redirect_uri, :scope]
31-
optional_params = [:nonce, :state]
32-
required_params.each do |key|
33-
params.require key
34-
end
35-
if params[:response_type] != 'code'
36-
raise HttpError::BadRequest.new('only respose_type=code is supported')
37-
end
38-
params.permit *(required_params + optional_params)
30+
def require_client
31+
@client = Client.find_by(identifier: oauth_request.client_id) or oauth_request.invalid_request!
32+
@redirect_uri = oauth_request.verify_redirect_uri! @client.redirect_uri
3933
end
40-
helper_method :accepted_params
4134

4235
def requested_scopes
43-
@requested_scopes ||= Scope.where name: accepted_params[:scope].split
36+
@requested_scopes ||= Scope.where(name: oauth_request.scope.split)
4437
end
4538
helper_method :requested_scopes
4639

47-
def current_client
48-
@current_client ||= Client.find_by!(
49-
identifier: accepted_params[:client_id],
50-
redirect_uri: accepted_params[:redirect_uri]
51-
)
40+
def require_response_type_code
41+
unless oauth_request.response_type == :code
42+
oauth_request.unsupported_response_type!
43+
end
5244
end
53-
helper_method :current_client
5445
end
+12-2
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
module Concerns
22
module Authentication
33
def current_account
4-
# NOTE: implement end-user authentication logic by your own
5-
@current_account ||= Account.first || Account.create
4+
@current_account
65
end
76

87
def current_token
98
@current_token ||= request.env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN]
109
end
1110

11+
def require_authentication
12+
# NOTE: implement end-user authentication logic by your own
13+
authenticate(
14+
Account.first || Account.create
15+
)
16+
end
17+
1218
def require_access_token
1319
unless current_token
1420
raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new
1521
end
1622
end
23+
24+
def authenticate(account)
25+
@current_account = account
26+
end
1727
end
1828
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module Concerns
2+
module ConnectEndpoint
3+
extend ActiveSupport::Concern
4+
5+
included do
6+
helper_method :oauth_request
7+
rescue_from Rack::OAuth2::Server::Authorize::BadRequest, with: :handle_oauth_error!
8+
end
9+
10+
def oauth_request
11+
request.env[Rack::OAuth2::Server::Rails::REQUEST]
12+
end
13+
14+
def oauth_response
15+
request.env[Rack::OAuth2::Server::Rails::RESPONSE]
16+
end
17+
18+
def oauth_error
19+
request.env[Rack::OAuth2::Server::Rails::ERROR]
20+
end
21+
22+
def handle_oauth_error!(e)
23+
if e.redirect?
24+
raise e # NOTE: rack middleware should handle this error.
25+
else
26+
render text: e.message, status: e.status
27+
end
28+
end
29+
30+
def require_oauth_request
31+
if oauth_error
32+
raise oauth_error
33+
end
34+
unless oauth_request && oauth_response
35+
raise 'should\'t happen'
36+
end
37+
end
38+
end
39+
end

app/controllers/user_infos_controller.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class UserInfosController < ApplicationController
2-
before_filter :require_access_token
2+
before_action :require_access_token
33

44
def show
55
render json: current_token.account.to_response_object(current_token)

app/views/authorizations/new.html.erb

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<article>
2-
<h2>Authorization Request by <%= current_client.name %></h2>
3-
<%= form_for authorization do |f| %>
2+
<h2>Authorization Request by <%= @client.name %></h2>
3+
<%= form_tag authorizations_path do %>
44
<ul>
55
<% requested_scopes.each do |scope| %>
66
<li><%= scope.name %></li>
77
<% end %>
88
</ul>
9-
<% accepted_params.each do |key, value| %>
10-
<%= hidden_field_tag key, value %>
9+
<% [:client_id, :response_type, :redirect_uri, :scope, :state, :nonce].each do |key| %>
10+
<%= hidden_field_tag key, oauth_request.send(key) %>
1111
<% end %>
12+
<p><%= submit_tag :deny %></p>
1213
<p><%= submit_tag :approve %></p>
1314
<% end %>
1415
</article>

config/application.rb

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Application < Rails::Application
1313
# -- all .rb files in that directory are automatically loaded.
1414
config.autoload_paths += %W(#{config.root}/lib)
1515

16+
config.middleware.use Rack::OAuth2::Server::Rails::Authorize
1617
config.middleware.use Rack::OAuth2::Server::Resource::Bearer, 'OpenID Connect' do |req|
1718
AccessToken.valid.find_by(token: req.access_token) ||
1819
req.invalid_token!

sample_rp.rb

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
require 'openid_connect'
2+
3+
OpenIDConnect.debug!
4+
5+
client = OpenIDConnect::Client.new(
6+
identifier: 'rp.dev',
7+
secret: '42347d901a6686a533067285ed13ee1b475121a6ece10446299f4be62e4e4bfc',
8+
redirect_uri: 'http://rp.dev/providers/3/open_id',
9+
host: 'op2.dev',
10+
scheme: 'http',
11+
authorization_endpoint: '/authorizations/new',
12+
token_endpoint: '/tokens',
13+
userinfo_endpoint: '/user_info'
14+
)
15+
16+
redirect_uri = client.authorization_uri(
17+
scope: [:email, :profile],
18+
state: SecureRandom.hex(8),
19+
nonce: SecureRandom.hex(8)
20+
)
21+
22+
puts redirect_uri
23+
`open "#{redirect_uri}"`
24+
25+
print 'code: ' and STDOUT.flush
26+
code = gets.chop
27+
28+
client.authorization_code = code
29+
client.access_token!

0 commit comments

Comments
 (0)