opro 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,19 +7,19 @@ class Opro::Oauth::ClientAppController < OproController
7
7
 
8
8
  # Show all client applications belonging to the current user
9
9
  def index
10
- @client_apps = Opro::Oauth::ClientApp.where(:user_id => current_user.id)
10
+ @client_apps = Opro::Oauth::ClientApp.where(user_id: current_user.id)
11
11
  end
12
12
 
13
13
  def show
14
- @client_app = Opro::Oauth::ClientApp.where(:id => params[:id], :user_id => current_user.id).first
14
+ @client_app = Opro::Oauth::ClientApp.where(id: params[:id], user_id: current_user.id).first
15
15
  end
16
16
 
17
17
  def edit
18
- @client_app = Opro::Oauth::ClientApp.where(:id => params[:id], :user_id => current_user.id).first
18
+ @client_app = Opro::Oauth::ClientApp.where(id: params[:id], user_id: current_user.id).first
19
19
  end
20
20
 
21
21
  def update
22
- @client_app = Opro::Oauth::ClientApp.where(:id => params[:id], :user_id => current_user.id).first
22
+ @client_app = Opro::Oauth::ClientApp.where(id: params[:id], user_id: current_user.id).first
23
23
  @client_app.name = params[:opro_oauth_client_app][:name]
24
24
  if @client_app.save
25
25
  redirect_to oauth_client_app_path(@client_app)
@@ -8,38 +8,29 @@ class Opro::Oauth::TestsController < OproController
8
8
 
9
9
  def show
10
10
  result = oauth_result(params)
11
- respond_to do |format|
12
- format.html do
13
- render :text => result.to_json, :status => result[:status], :layout => true
14
- end
15
- format.json do
16
- render :json => result, :status => result[:status]
17
- end
18
- end
11
+ render_result(result)
19
12
  end
20
13
 
21
14
  def create
22
15
  result = oauth_result(params)
23
- respond_to do |format|
24
- format.html do
25
- render :text => result.to_json, :status => result[:status], :layout => true
26
- end
27
- format.json do
28
- render :json => result, :status => result[:status]
29
- end
30
- end
16
+ render_result(result)
31
17
  end
32
18
 
33
19
  def destroy
34
20
  result = if valid_oauth?
35
- {:status => 200, :message => 'OH NO!!! OAuth is disabled on this action; this is bad', :params => params}
21
+ {status: 200, message: 'OH NO!!! OAuth is disabled on this action; this is bad', params: params}
36
22
  else
37
- {:status => :unauthorized, :message => "OAuth is disabled on this action; this is the correct result!", :params => params}
23
+ {status: :unauthorized, message: "OAuth is disabled on this action; this is the correct result!", params: params}
38
24
  end
25
+ render_result(result)
26
+ end
39
27
 
28
+ private
29
+
30
+ def render_result(result)
40
31
  respond_to do |format|
41
32
  format.html do
42
- render :text => result.to_json, :status => result[:status], :layout => true
33
+ render :text => result.to_json, :status => result[:status], :layout => true
43
34
  end
44
35
  format.json do
45
36
  render :json => result, :status => result[:status]
@@ -47,13 +38,11 @@ class Opro::Oauth::TestsController < OproController
47
38
  end
48
39
  end
49
40
 
50
- private
51
-
52
41
  def oauth_result(options)
53
42
  if valid_oauth?
54
- {:status => 200, :message => 'OAuth worked!', :params => options, :user_id => oauth_user.id }
43
+ {status: 200, message: 'OAuth worked!', params: options, user_id: oauth_user.id }
55
44
  else
56
- {:status => :unauthorized, :message => "OAuth did not work :( #{generate_oauth_error_message!}", :params => params}
45
+ {status: :unauthorized, message: "OAuth did not work :( #{generate_oauth_error_message!}", params: params}
57
46
  end
58
47
  end
59
48
  end
@@ -9,42 +9,49 @@ class Opro::Oauth::TokenController < OproController
9
9
  def create
10
10
  # Find the client application
11
11
  application = Opro::Oauth::ClientApp.authenticate(params[:client_id], params[:client_secret])
12
-
13
- if application.nil?
14
- render :json => {:error => app_not_found_error(params)}, :status => :unauthorized and return
12
+ auth_grant = auth_grant_for(application, params)
13
+
14
+ if auth_grant.present?
15
+ auth_grant.refresh!
16
+ render :json => { access_token: auth_grant.access_token,
17
+ # http://tools.ietf.org/html/rfc6749#section-5.1
18
+ token_type: Opro.token_type || 'bearer',
19
+ refresh_token: auth_grant.refresh_token,
20
+ expires_in: auth_grant.expires_in }
21
+ else
22
+ render_error debug_msg(params, application)
15
23
  end
24
+ end
16
25
 
26
+ private
27
+
28
+ def auth_grant_for(application, params)
17
29
  if params[:code]
18
- auth_grant = Opro::Oauth::AuthGrant.auth_with_code!(params[:code], application.id)
30
+ Opro::Oauth::AuthGrant.find_by_code_app(params[:code], application)
19
31
  elsif params[:refresh_token]
20
- auth_grant = Opro::Oauth::AuthGrant.find_for_refresh(params[:refresh_token], application.id)
32
+ Opro::Oauth::AuthGrant.find_by_refresh_app(params[:refresh_token], application)
21
33
  elsif params[:password].present? || params[:grant_type] == "password"|| params[:grant_type] == "bearer"
22
- user = ::Opro.find_user_for_all_auths!(self, params) if Opro.password_exchange_enabled? && oauth_valid_password_auth?(params[:client_id], params[:client_secret])
23
- auth_grant = Opro::Oauth::AuthGrant.auth_with_user!(user, application.id) if user.present?
34
+ return false unless Opro.password_exchange_enabled?
35
+ return false unless oauth_valid_password_auth?(params[:client_id], params[:client_secret])
36
+ user = ::Opro.find_user_for_all_auths!(self, params)
37
+ return false unless user.present?
38
+ auth_grant = Opro::Oauth::AuthGrant.find_or_create_by_user_app(user, application)
39
+ auth_grant.update_permissions if auth_grant.present?
40
+ auth_grant
24
41
  end
25
-
26
- if auth_grant.blank?
27
- render :json => {:error => debug_error_msg(params) }, :status => :unauthorized and return
28
- end
29
-
30
- auth_grant.refresh!
31
- render :json => { :access_token => auth_grant.access_token,
32
- :refresh_token => auth_grant.refresh_token,
33
- :expires_in => auth_grant.expires_in }
34
42
  end
35
43
 
36
- private
37
-
38
- def debug_error_msg(options)
44
+ def debug_msg(options, app)
39
45
  msg = "Could not find a user that belongs to this application"
46
+ msg << " based on client_id=#{options[:client_id]} and client_secret=#{options[:client_secret]}" if app.blank?
40
47
  msg << " & has a refresh_token=#{options[:refresh_token]}" if options[:refresh_token]
41
48
  msg << " & has been granted a code=#{options[:code]}" if options[:code]
42
49
  msg << " using username and password" if options[:password]
43
50
  msg
44
51
  end
45
52
 
46
- def app_not_found_error(options)
47
- "Could not find application based on client_id=#{options[:client_id]} and client_secret=#{options[:client_secret]}"
53
+ def render_error(msg)
54
+ render :json => {:error => msg }, :status => :unauthorized
48
55
  end
49
56
 
50
- end
57
+ end
@@ -18,7 +18,7 @@ class Opro::Oauth::AuthGrant < ActiveRecord::Base
18
18
 
19
19
  serialize :permissions, Hash
20
20
 
21
- attr_accessible :code, :access_token, :refresh_token, :access_token_expires_at, :permissions, :user_id, :user, :application_id, :application
21
+ # attr_accessible :code, :access_token, :refresh_token, :access_token_expires_at, :permissions, :user_id, :user, :application_id, :application
22
22
 
23
23
  def can?(value)
24
24
  HashWithIndifferentAccess.new(permissions)[value]
@@ -47,20 +47,34 @@ class Opro::Oauth::AuthGrant < ActiveRecord::Base
47
47
  find_app_for_token.try(:user)
48
48
  end
49
49
 
50
- def self.auth_with_code!(code, application_id)
51
- auth_grant = self.where("code = ? AND application_id = ?", code, application_id).first
50
+ def self.find_by_code_app(code, app)
51
+ app_id = app.is_a?(Integer) ? app : app.id
52
+ auth_grant = self.where("code = ? AND application_id = ?", code, app_id).first
52
53
  end
53
54
 
54
- def self.auth_with_user!(user, applicaiton_id, permissions = ::Opro.request_permissions)
55
- return false unless user
56
- permissions_hash = permissions.each_with_object({}) {|element, hash| hash[element] = true }
57
- auth_grant = self.where(:user_id => user.id, :application_id => applicaiton_id).first
58
- auth_grant ||= self.create(:user_id => user.id, :application_id => applicaiton_id)
59
- auth_grant.update_attributes(:permissions => permissions_hash)
60
- auth_grant
55
+ # turns array of permissions into a hash
56
+ # [:write, :read] => {write: true, read: true}
57
+ def default_permissions
58
+ ::Opro.request_permissions.each_with_object({}) {|element, hash| hash[element] = true }
61
59
  end
62
60
 
63
- def self.find_for_refresh(refresh_token, application_id)
61
+ def self.find_or_create_by_user_app(user, app)
62
+ app_id = app.is_a?(Integer) ? app : app.id
63
+ auth_grant = self.where(:user_id => user.id, :application_id => app_id).first
64
+ auth_grant ||= begin
65
+ auth_grant = self.new
66
+ auth_grant.user_id = user.id
67
+ auth_grant.application_id = app_id
68
+ auth_grant.save
69
+ auth_grant
70
+ end
71
+ end
72
+
73
+ def update_permissions(permissions = default_permissions)
74
+ self.permissions = permissions and save if self.permissions != permissions
75
+ end
76
+
77
+ def self.find_by_refresh_app(refresh_token, application_id)
64
78
  self.where("refresh_token = ? AND application_id = ?", refresh_token, application_id).first
65
79
  end
66
80
 
@@ -12,15 +12,24 @@ class Opro::Oauth::ClientApp < ActiveRecord::Base
12
12
 
13
13
  serialize :permissions, Hash
14
14
 
15
- attr_accessible :user, :name, :app_id, :client_secret, :app_secret, :secret
15
+ # attr_accessible :user, :name, :app_id, :client_secret, :app_secret, :secret
16
16
 
17
+ def self.find_by_client_id(client_id)
18
+ where(app_id: client_id).first
19
+ end
17
20
 
18
21
  def self.authenticate(app_id, app_secret)
19
22
  where(["app_id = ? AND app_secret = ?", app_id, app_secret]).first
20
23
  end
21
24
 
22
25
  def self.create_with_user_and_name(user, name)
23
- create(:user => user, :name => name, :app_id => generate_unique_app_id, :app_secret => SecureRandom.hex(16))
26
+ client_app = self.new
27
+ client_app.user = user
28
+ client_app.name = name
29
+ client_app.app_id = generate_unique_app_id
30
+ client_app.app_secret = SecureRandom.hex(16)
31
+ client_app.save
32
+ client_app
24
33
  end
25
34
 
26
35
  def self.generate_unique_app_id(app_id = SecureRandom.hex(16))
@@ -20,7 +20,7 @@
20
20
  <% end %>
21
21
  </ul>
22
22
 
23
- <%= f.submit 'Authorize This Application', :id => 'oauthAuthorize' %>
23
+ <%= f.submit 'Authorize This Application', :id => 'oauthAuthorize', :class => 'btn btn-primary' %>
24
24
  <%- end -%>
25
25
 
26
26
  <%= button_to 'Decline this Request', request.referrer||'/', :id => 'oauthNoAuthorize' %>
@@ -5,8 +5,8 @@
5
5
  <h2>Quick Links</h2>
6
6
  <ul>
7
7
  <li><%= link_to 'Quick Start', oauth_doc_path(:quick_start) %></li>
8
- <li><%= link_to 'Curl', oauth_doc_path(:curl) %></li>
9
8
  <li><%= link_to 'OAuth', oauth_doc_path(:oauth) %></li>
9
+ <li><%= link_to 'Curl', oauth_doc_path(:curl) %></li>
10
10
 
11
11
  <% if ::Opro.request_permissions.present? %>
12
12
  <li><%= link_to 'Permisions', oauth_doc_path(:permissions) %></li>
@@ -6,9 +6,6 @@
6
6
 
7
7
  With curl, we're able to arbitrarily add parameters to our requests and send using arbitrary HTTP verbs (GET/POST/DELETE) that are difficult to simulate in the browser. If you need to `POST` data to a url, doing so with curl is much easier than constructing a form for testing.
8
8
 
9
- # Hurl
10
-
11
- [Hurl](http://hurl.it/) is an open source browser-based `curl` implementation. If you're going to do quite a few curl requests, using it can be easier than the command line.
12
9
 
13
10
  ## How do I use it?
14
11
 
@@ -26,6 +23,9 @@ You can get the entire contents of a web document by simply calling curl with th
26
23
  You can ask for the headers of a request by adding the `-I` flag to a curl command:
27
24
 
28
25
  $ curl https://www.google.com -I
26
+
27
+ The response may look something like this:
28
+
29
29
  HTTP/1.1 200 OK
30
30
  Expires: -1
31
31
  Cache-Control: private, max-age=0
@@ -48,4 +48,6 @@ You can specify the type of request you make in curl (GET, POST, PUT, DELETE, et
48
48
 
49
49
  $ curl -X POST <%= root_url %>products
50
50
 
51
+ # Hurl
51
52
 
53
+ [Hurl](http://hurl.it/) is an open source browser-based `curl` implementation. If you're going to do quite a few curl requests, using it can be easier than the command line.
@@ -19,7 +19,7 @@ To perform any type of request other than a [GET](http://en.wikipedia.org/wiki/H
19
19
  As a client application, you can request specific scopes while you are authorizing a user. If no scope is specified, all permissions will be requested. This is an example of an application with client id of `3234myClientId5678` specifying that they want `write` access for their app:
20
20
 
21
21
 
22
- <%= oauth_authorize_url(:client_id => "3234myClientId5678", :protocol => @protocol) + "&scope[]=write" %>
22
+ <%= oauth_new_url(:client_id => "3234myClientId5678", :protocol => @protocol) + "&scope[]=write" %>
23
23
 
24
24
 
25
25
  While authorizing your application a user can choose to grant or reject individual permissions.
@@ -30,7 +30,7 @@ Once you've registered an app successfully we can start to build an OAuth applic
30
30
 
31
31
  Now that you have a client application, you'll want to give it access to a user account. Open a new browser window and log in with a user account, then give your application permission by visiting the url below (swap out '3234myClientId5678' for your client id and '14321myClientSecret8765' for your client secret)
32
32
 
33
- <%= oauth_authorize_url(:protocol => @protocol, :redirect_uri => "/", :client_id => "3234myClientId5678", :client_secret => "14321myClientSecret8765" ) %>
33
+ <%= oauth_new_url(:protocol => @protocol, :redirect_uri => "/", :client_id => "3234myClientId5678", :client_secret => "14321myClientSecret8765" ) %>
34
34
 
35
35
 
36
36
  This should land you on a page asking if you would like to grant permission to the application. If not, make sure you're logged in and you put the correct client id in the url.
@@ -53,10 +53,12 @@ We'll be using [Curl](<%= oauth_doc_path(:curl) %>) to go through the process of
53
53
  You'll want to make sure to replace `client_id`, `client_secret`, and `code` with your values.
54
54
 
55
55
 
56
- $ curl '<%= oauth_token_url(:protocol => @protocol,
56
+ $ curl -X POST -d '' '<%= oauth_token_url(
57
+ :protocol => @protocol,
57
58
  :client_id => "3234myClientId5678",
58
59
  :client_secret => "14321myClientSecret8765",
59
- :code => "4857goldfish827423") %>'
60
+ :code => "4857goldfish827423",
61
+ :format => "json") %>'
60
62
 
61
63
 
62
64
  You should get back a response that looks like this:
@@ -73,7 +75,7 @@ Now that we've gone through all the hard work of getting an access token, you ca
73
75
 
74
76
  Try it out for yourself. Replace the access token below with the one you received and run this curl command:
75
77
 
76
- $ curl "<%= oauth_test_url(:show_me_the_money, :access_token => '9693accessTokena7ca570bbaf') %>"
78
+ $ curl "<%= oauth_test_url(:show_me_the_money, :access_token => '9693accessTokena7ca570bbaf', :format => 'json') %>"
77
79
 
78
80
 
79
81
 
@@ -81,7 +83,7 @@ You should see a successful result (again, don't forget to replace the example a
81
83
 
82
84
  You can also use a header to pass the OAuth token:
83
85
 
84
- $ curl -H "Authorization: token 9693accessTokena7ca570bbaf" "<%= oauth_test_url(:show_me_the_money) %>"
86
+ $ curl -H "Authorization: token 9693accessTokena7ca570bbaf" "<%= oauth_test_url(:show_me_the_money, :format => 'json') %>"
85
87
 
86
88
 
87
89
  ## Security
@@ -89,3 +91,5 @@ You can also use a header to pass the OAuth token:
89
91
  Don't share your client application's secret or any user's access_token with unknown or untrusted parties. Always use https when available and don't write any of these values to your application's logs.
90
92
 
91
93
 
94
+
95
+
@@ -10,7 +10,7 @@ If a token has expired or you simply wish to receive a new `access_token` you ca
10
10
 
11
11
 
12
12
 
13
- $ curl '<%= oauth_token_url(:protocol => @protocol,
13
+ $ curl -X POST -d '' '<%= oauth_token_url(:protocol => @protocol,
14
14
  :client_id => "3234myClientId5678",
15
15
  :client_secret => "14321myClientSecret8765",
16
16
  :refresh_token => "4857goldfish827423") %>'
@@ -19,29 +19,19 @@ module Opro
19
19
  set_login_logout_methods
20
20
  end
21
21
 
22
+ # sets up defaults for common auth providers
22
23
  def self.set_login_logout_methods
23
- case auth_strategy
24
+ klass = case auth_strategy
24
25
  when :devise
25
- login_method { |controller, current_user| controller.sign_in(current_user, :bypass => true) }
26
- logout_method { |controller, current_user| controller.sign_out(current_user) }
27
- authenticate_user_method { |controller| controller.authenticate_user! }
28
-
29
- find_user_for_auth do |controller, params|
30
- return false if params[:password].blank?
31
- find_params = params.each_with_object({}) {|(key,value), hash| hash[key] = value if Devise.authentication_keys.include?(key.to_sym) }
32
- # Try to get fancy, some clients have :username hardcoded, if we have nothing in our find hash
33
- # we can make an educated guess here
34
- if find_params.blank? && params[:username].present?
35
- find_params = { Devise.authentication_keys.first => params[:username] }
36
- end
37
- user = User.where(find_params).first if find_params.present?
38
- return false unless user.present?
39
- return false unless user.valid_password?(params[:password])
40
- user
41
- end
26
+ AuthProvider::Devise
42
27
  else
43
- # nothing
28
+ auth_strategy if auth_strategy.is_a? Class
44
29
  end
30
+ return false unless klass.present?
31
+ login_method { |controller, current_user| klass.new(controller).login_method(current_user) }
32
+ logout_method { |controller, current_user| klass.new(controller).logout_method(current_user) }
33
+ find_user_for_auth { |controller, params| klass.new(controller).find_user_for_auth(params) }
34
+ authenticate_user_method { |controller| klass.new(controller).authenticate_user_method }
45
35
  end
46
36
 
47
37
  # Used by application controller to log user in
@@ -120,13 +110,21 @@ module Opro
120
110
  @user
121
111
  end
122
112
 
123
-
124
113
  # default to no match
125
114
  def self.header_auth_regex
126
115
  @header_auth_regex || /$^/
127
116
  end
128
117
 
129
- # Allows a user to set define a custom authorization regular expression
118
+
119
+ def self.token_type=(token_type)
120
+ @token_type = token_type
121
+ end
122
+
123
+ def self.token_type
124
+ @token_type
125
+ end
126
+
127
+ # Allows a user to define a custom authorization regular expression
130
128
  def self.header_auth_regex=(regexstring)
131
129
  raise "not a regex" unless regexstring.is_a? Regexp
132
130
  @header_auth_regex = regexstring
@@ -152,7 +150,7 @@ module Opro
152
150
  @find_for_authentication ||= []
153
151
  @find_for_authentication << convert_to_lambda(&block)
154
152
  else
155
- @find_for_authentication or raise 'find_for_authentication not set, please specify an oPRO auth_strategy in config/initializers/opro.rb'
153
+ @find_for_authentication or raise 'find_user_for_auth not set, please specify an oPRO auth_strategy in config/initializers/opro.rb'
156
154
  end
157
155
  end
158
156
 
@@ -165,8 +163,10 @@ module Opro
165
163
  end
166
164
  end
167
165
 
166
+
168
167
  require 'opro/controllers/concerns/rate_limits'
169
168
  require 'opro/controllers/concerns/error_messages'
170
169
  require 'opro/controllers/concerns/permissions'
171
170
  require 'opro/controllers/application_controller_helper'
171
+ require 'opro/auth_provider/devise'
172
172
  require 'opro/engine'
@@ -0,0 +1,37 @@
1
+ module Opro
2
+ module AuthProvider
3
+ class Devise
4
+ attr_reader :controller
5
+
6
+ def initialize(controller)
7
+ @controller = controller
8
+ end
9
+
10
+ def login_method(current_user)
11
+ controller.sign_in(current_user, :bypass => true)
12
+ end
13
+
14
+ def logout_method(current_user)
15
+ controller.sign_out(current_user)
16
+ end
17
+
18
+ def authenticate_user_method
19
+ controller.authenticate_user!
20
+ end
21
+
22
+ def find_user_for_auth(params)
23
+ return false if params[:password].blank?
24
+ find_params = params.each_with_object({}) {|(key,value), hash| hash[key] = value if ::Devise.authentication_keys.include?(key.to_sym) }
25
+ # Try to get fancy, some clients have :username hardcoded, if we have nothing in our find hash
26
+ # we can make an educated guess here
27
+ if find_params.blank? && params[:username].present?
28
+ find_params = { ::Devise.authentication_keys.first => params[:username] }
29
+ end
30
+ user = User.where(find_params).first if find_params.present?
31
+ return false unless user.present?
32
+ return false unless user.valid_password?(params[:password])
33
+ user
34
+ end
35
+ end
36
+ end
37
+ end