oauth2_provider 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,3 +1,97 @@
1
+ [f15eb88 | Tue Aug 31 23:25:50 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
2
+
3
+ * Bumping up version number for a 0.2.0 release!
4
+
5
+ [05c5534 | Wed Aug 25 17:40:04 UTC 2010] Janmejay Singh <singh.janmejay@gmail.com>
6
+
7
+ * plugin when loaded in jruby/rails app(initialized by jruby-rack servlet), in production mode, was failing to find files/load missing constants(even though files are present in path). Fixed the problem by eger loading necessary files.
8
+
9
+ [79c14f0 | Mon Aug 23 18:24:17 UTC 2010] David Rice <david.rice@gmail.com>
10
+
11
+ * add ids and classes to HTML to allow for styling by host application; remove oauth client show view as it was redundant to the list view
12
+
13
+ [0ff4cc7 | Tue Aug 10 21:23:00 UTC 2010] Janmejay Singh <singh.janmejay@gmail.com>
14
+
15
+ * allowed silencing 'using datasource...' message by an environment variable, message is shown unless ENV['LOAD_OAUTH_SILENTLY'] is set
16
+
17
+ [c59ef9f | Tue Aug 10 20:43:53 UTC 2010] Janmejay Singh <singh.janmejay@gmail.com>
18
+
19
+ * added environment variables to make route prefixing possible
20
+
21
+ [e051873 | Fri Aug 06 02:18:36 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
22
+
23
+ * user_id_for_oauth_access_token is nil if the token passed using the 'Authorization' header has expired.
24
+
25
+ [740104a | Fri Aug 06 01:19:28 UTC 2010] Janmejay Singh <singh.janmejay@gmail.com>
26
+
27
+ * refactored model_base to pick datasource using a method instead of @@datasource, this makes it easy for plugin users to override what datasource instance is used. jruby-rack initializes @app on first request(insteed of servlet initialization), so it is important to do this lazily
28
+
29
+ [a3728a9 | Fri Aug 06 01:16:27 UTC 2010] Janmejay Singh <singh.janmejay@gmail.com>
30
+
31
+ * user level service approval now has forgery protection enabled + disabled forgery_protection for api request(/oauth/token)
32
+
33
+ [2145cd2 | Tue Aug 03 18:15:15 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
34
+
35
+ * Fixed url munging issues because our model objects are not AR based. Duck typing!!
36
+
37
+ [c6d43b3 | Mon Aug 02 17:37:14 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
38
+
39
+ * KP/WPC -
40
+
41
+ * Autodiscover the datasource based on whether ActiveRecord is available.
42
+ * Default to using InMemoryDatasource if ActiveRecord is not available, and print a warning.
43
+
44
+ [ddc56ca | Sat Jul 31 00:55:47 UTC 2010] wpc <alex.hal9000@gmail.com>
45
+
46
+ * Specify data type for column for ModelBase. (by default is string type)
47
+
48
+ [9546cd7 | Fri Jul 30 23:22:43 UTC 2010] wpc <alex.hal9000@gmail.com>
49
+
50
+ * KP/WPC use eval instead of constantize for intiailze custom data source, because constantize dose not work on java class
51
+
52
+ [c52a5b6 | Fri Jul 30 23:19:14 UTC 2010] wpc <alex.hal9000@gmail.com>
53
+
54
+ * KP/WPC refactoring for removing all find_all_* methods
55
+
56
+ [136bca5 | Fri Jul 30 22:57:51 UTC 2010] wpc <alex.hal9000@gmail.com>
57
+
58
+ * KP/WPC - removed some find methods.
59
+
60
+ [233b20c | Fri Jul 30 22:37:00 UTC 2010] wpc <alex.hal9000@gmail.com>
61
+
62
+ * KP/WPC - Add some tests for ModelBase. Removed some redundant tests from oauth_client_test which were really ModelBase tests.
63
+
64
+ [5e43b90 | Fri Jul 30 21:05:40 UTC 2010] wpc <alex.hal9000@gmail.com>
65
+
66
+ * KP/WPC change expires_at type to integer, so that DataSource don't need to do Date type converting.
67
+
68
+ [027ded7 | Fri Jul 30 00:41:36 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
69
+
70
+ * Renamed a class.
71
+
72
+ [31903c2 | Fri Jul 30 00:05:24 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
73
+
74
+ * KP/WPC - Added an example in memory datasource to store oauth DTO objects.
75
+
76
+ [bd4f9db | Thu Jul 29 22:24:06 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
77
+
78
+ * KP/WPC - Remove all dependencies on AR.
79
+
80
+ [cf2b818 | Thu Jul 29 20:53:09 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
81
+
82
+ * KP/WPC - [cleanup] refactored our classes into their own files.
83
+
84
+ [1f8f120 | Thu Jul 29 20:46:36 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
85
+
86
+ * Remove empty file.
87
+
88
+ [4072a40 | Thu Jul 29 19:16:32 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
89
+
90
+ * KP/WPC - Remove dependency on AR.
91
+
92
+ Decouple the OauthClient from AR.
93
+ Rolled out our own AR 'clone' that delegates DB operations to a DTO behind the source.
94
+
1
95
  [20b81b6 | Sat Jul 24 00:30:26 UTC 2010] Ketan Padegaonkar <KetanPadegaonkar@gmail.com>
2
96
 
3
97
  * Bump up version number for release.
data/README.textile CHANGED
@@ -15,6 +15,8 @@ OAuth is an open-source specification for building a framework for allowing a th
15
15
 
16
16
  A very good overview of the basic OAuth workflow is "here":http://hueniverse.com/2007/10/beginners-guide-to-oauth-part-ii-protocol-workflow/.
17
17
 
18
+ As some of this is not always easy to grok on first pass, we also put together "some videos":http://www.youtube.com/view_play_list?p=675281900139F609 to give a step-by-step introduction to OAuth.
19
+
18
20
  Common terms:
19
21
 
20
22
  * Provider/Resource Owner - the app that hosts the protected resource. A real world example is Twitter which uses OAuth as the protocol for all its clients.
@@ -48,7 +48,7 @@ module Oauth2
48
48
  return false
49
49
  end
50
50
 
51
- @client = OauthClient.find_by_client_id(params[:client_id])
51
+ @client = OauthClient.find_one(:client_id, params[:client_id])
52
52
 
53
53
  if @client.nil?
54
54
  redirect_to "#{params[:redirect_uri]}?error=invalid-client-id"
@@ -26,7 +26,8 @@ module Oauth2
26
26
 
27
27
  if @oauth_client.save
28
28
  flash[:notice] = 'OauthClient was successfully created.'
29
- redirect_to(@oauth_client)
29
+ redirect_to :action => 'index'
30
+ return
30
31
  else
31
32
  render :action => "new"
32
33
  end
@@ -37,7 +38,8 @@ module Oauth2
37
38
 
38
39
  if @oauth_client.update_attributes(params[:oauth_client])
39
40
  flash[:notice] = 'OauthClient was successfully updated.'
40
- redirect_to(@oauth_client)
41
+ redirect_to :action => 'index'
42
+ return
41
43
  else
42
44
  render :action => "edit"
43
45
  end
@@ -4,43 +4,42 @@
4
4
  module Oauth2
5
5
  module Provider
6
6
  class OauthTokenController < ApplicationController
7
+ skip_before_filter :verify_authenticity_token
7
8
 
8
9
  def get_token
9
10
 
10
- authorization = OauthAuthorization.find_by_code(params[:code])
11
- authorization.delete unless authorization.nil?
11
+ authorization = OauthAuthorization.find_one(:code, params[:code])
12
+ authorization.destroy unless authorization.nil?
12
13
 
13
- original_token = OauthToken.find_by_refresh_token(params[:refresh_token])
14
- original_token.delete unless original_token.nil?
14
+ original_token = OauthToken.find_one(:refresh_token, params[:refresh_token])
15
+ original_token.destroy unless original_token.nil?
15
16
 
16
17
  unless ['authorization-code', 'refresh-token'].include?(params[:grant_type])
17
- render_error('unsupported-grant-type')
18
+ render_error('unsupported-grant-type', "Grant type #{params[:grant_type]} is not supported!")
18
19
  return
19
20
  end
20
21
 
21
- client = OauthClient.find_by_client_id_and_client_secret(
22
- params[:client_id], params[:client_secret]
23
- )
24
-
25
- if client.nil?
26
- render_error('invalid-client-credentials')
22
+ client = OauthClient.find_one(:client_id, params[:client_id])
23
+
24
+ if client.nil? || client.client_secret != params[:client_secret]
25
+ render_error('invalid-client-credentials', 'Invalid client credentials!')
27
26
  return
28
27
  end
29
28
 
30
29
  if client.redirect_uri != params[:redirect_uri]
31
- render_error('invalid-grant')
30
+ render_error('invalid-grant', 'Redirect uri mismatch!')
32
31
  return
33
32
  end
34
33
 
35
34
  if params[:grant_type] == 'authorization-code'
36
- if authorization.nil? || authorization.expired? || authorization.oauth_client != client
37
- render_error('invalid-grant')
35
+ if authorization.nil? || authorization.expired? || authorization.oauth_client.id != client.id
36
+ render_error('invalid-grant', "Authorization expired or invalid!")
38
37
  return
39
38
  end
40
39
  token = authorization.generate_access_token
41
40
  else # refresh-token
42
- if original_token.nil? || original_token.oauth_client != client
43
- render_error('invalid-grant')
41
+ if original_token.nil? || original_token.oauth_client.id != client.id
42
+ render_error('invalid-grant', 'Refresh token is invalid!')
44
43
  return
45
44
  end
46
45
  token = original_token.refresh
@@ -50,8 +49,8 @@ module Oauth2
50
49
  end
51
50
 
52
51
  private
53
- def render_error(error_code)
54
- render :status => :bad_request, :json => {:error => error_code}.to_json
52
+ def render_error(error_code, description)
53
+ render :status => :bad_request, :json => {:error => error_code, :error_description => description}.to_json
55
54
  end
56
55
 
57
56
  end
@@ -6,7 +6,7 @@ module Oauth2
6
6
  class OauthUserTokensController < ApplicationController
7
7
 
8
8
  def index
9
- @tokens = OauthToken.find_all_by_user_id(current_user_id_for_oauth)
9
+ @tokens = OauthToken.find_all_with(:user_id, current_user_id_for_oauth)
10
10
  end
11
11
 
12
12
  def revoke
@@ -15,12 +15,12 @@ module Oauth2
15
15
  render :text => "User not authorized to perform this action!", :status => :bad_request
16
16
  return
17
17
  end
18
- if token.user_id != current_user_id_for_oauth
18
+ if token.user_id.to_s != current_user_id_for_oauth
19
19
  render :text => "User not authorized to perform this action!", :status => :bad_request
20
20
  return
21
21
  end
22
22
 
23
- token.delete
23
+ token.destroy
24
24
  redirect_to :action => :index
25
25
  end
26
26
 
@@ -3,32 +3,34 @@
3
3
 
4
4
  module Oauth2
5
5
  module Provider
6
- class OauthAuthorization < ::ActiveRecord::Base
6
+ class OauthAuthorization < ModelBase
7
7
 
8
- belongs_to :oauth_client, :class_name => "Oauth2::Provider::OauthClient"
9
-
10
8
  EXPIRY_TIME = 1.hour
11
-
9
+ columns :user_id, :oauth_client_id, :code, :expires_at => :integer
10
+
11
+ def oauth_client
12
+ OauthClient.find_by_id(oauth_client_id)
13
+ end
14
+
12
15
  def generate_access_token
13
16
  token = oauth_client.create_token_for_user_id(user_id)
14
- self.delete
17
+ self.destroy
15
18
  token
16
19
  end
17
-
20
+
18
21
  def expires_in
19
22
  (Time.at(expires_at.to_i) - Clock.now).to_i
20
23
  end
21
-
24
+
22
25
  def expired?
23
26
  expires_in <= 0
24
27
  end
25
-
26
- protected
28
+
27
29
  def before_create
28
- self.expires_at = Clock.now + EXPIRY_TIME
30
+ self.expires_at = (Clock.now + EXPIRY_TIME).to_i
29
31
  self.code = ActiveSupport::SecureRandom.hex(32)
30
32
  end
31
-
33
+
32
34
  end
33
35
  end
34
36
  end
@@ -3,31 +3,41 @@
3
3
 
4
4
  module Oauth2
5
5
  module Provider
6
- class OauthClient < ActiveRecord::Base
7
-
6
+ class OauthClient < ModelBase
7
+
8
8
  validates_presence_of :name, :redirect_uri
9
- before_create :generate_keys
10
- has_many :oauth_tokens, :class_name => "Oauth2::Provider::OauthToken", :dependent => :delete_all
11
- has_many :oauth_authorizations, :class_name => "Oauth2::Provider::OauthAuthorization", :dependent => :delete_all
12
9
  validates_format_of :redirect_uri, :with => Regexp.new("^(https|http)://.+$")
10
+
11
+ columns :name, :client_id, :client_secret, :redirect_uri
13
12
 
14
13
  def create_token_for_user_id(user_id)
15
- oauth_tokens.create!(:user_id => user_id)
14
+ OauthToken.create!(:user_id => user_id, :oauth_client_id => id)
16
15
  end
17
16
 
18
17
  def create_authorization_for_user_id(user_id)
19
- oauth_authorizations.create!(:user_id => user_id)
18
+ OauthAuthorization.create!(:user_id => user_id, :oauth_client_id => id)
20
19
  end
21
-
22
20
  def self.model_name
23
21
  ActiveSupport::ModelName.new('OauthClient')
24
22
  end
23
+
24
+ def oauth_tokens
25
+ OauthToken.find_all_with(:oauth_client_id, id)
26
+ end
27
+
28
+ def oauth_authorizations
29
+ OauthAuthorization.find_all_with(:oauth_client_id, id)
30
+ end
25
31
 
26
- private
27
- def generate_keys
32
+ def before_create
28
33
  self.client_id = ActiveSupport::SecureRandom.hex(32)
29
34
  self.client_secret = ActiveSupport::SecureRandom.hex(32)
30
35
  end
36
+
37
+ def before_destroy
38
+ oauth_tokens.each(&:destroy)
39
+ oauth_authorizations.each(&:destroy)
40
+ end
31
41
 
32
42
  end
33
43
  end
@@ -3,36 +3,39 @@
3
3
 
4
4
  module Oauth2
5
5
  module Provider
6
- class OauthToken < ::ActiveRecord::Base
6
+ class OauthToken < ModelBase
7
+
8
+ columns :user_id, :oauth_client_id, :access_token, :refresh_token, :expires_at => :integer
7
9
 
8
- belongs_to :oauth_client, :class_name => "Oauth2::Provider::OauthClient"
9
-
10
10
  EXPIRY_TIME = 90.days
11
-
11
+
12
+ def oauth_client
13
+ OauthClient.find_by_id(oauth_client_id)
14
+ end
15
+
12
16
  def access_token_attributes
13
17
  {:access_token => access_token, :expires_in => expires_in, :refresh_token => refresh_token}
14
18
  end
15
-
19
+
16
20
  def expires_in
17
21
  (Time.at(expires_at.to_i) - Clock.now).to_i
18
22
  end
19
-
23
+
20
24
  def expired?
21
25
  expires_in <= 0
22
26
  end
23
-
27
+
24
28
  def refresh
25
- self.delete
29
+ self.destroy
26
30
  oauth_client.create_token_for_user_id(user_id)
27
31
  end
28
32
 
29
- protected
30
33
  def before_create
31
34
  self.access_token = ActiveSupport::SecureRandom.hex(32)
32
- self.expires_at = Clock.now + EXPIRY_TIME
35
+ self.expires_at = (Clock.now + EXPIRY_TIME).to_i
33
36
  self.refresh_token = ActiveSupport::SecureRandom.hex(32)
34
37
  end
35
-
38
+
36
39
  end
37
40
  end
38
41
  end
@@ -1,8 +1,8 @@
1
- <form action="<%= url_for(:action => :authorize) %>" method="post" id="oauth_authorize">
1
+ <% form_for(url_for(:action => :authorize), :html => {:id => 'oauth_authorize_form'}) do |f| -%>
2
2
  Do you wish to allow the service named '<%= @client.name %>' to access this application on your behalf? <input type="checkbox" name="authorize" id="authorize" value="1" />
3
3
  <input type="hidden" name="client_id" id="client_id" value="<%= params[:client_id] %>" />
4
4
  <input type="hidden" name="redirect_uri" id="redirect_uri" value="<%= params[:redirect_uri] %>" />
5
5
  <input type="hidden" name="response_type" id="response_type" value="<%= params[:response_type] %>" />
6
6
  <input type="hidden" name="state" id="state" value="<%= params[:state] %>" />
7
7
  <input type="submit" value="Submit" />
8
- </form>
8
+ <% end -%>
@@ -1,20 +1,20 @@
1
1
  <h1>Editing oauth_client</h1>
2
2
 
3
- <% form_for(@oauth_client) do |f| %>
3
+ <% form_for(@oauth_client, :html => {:id => 'oauth_client_edit_form', :class => nil}) do |f| %>
4
4
  <%= f.error_messages %>
5
5
 
6
- <p>
7
- <%= f.label :name %><br />
6
+ <div>
7
+ <%= f.label :name %>
8
8
  <%= f.text_field :name %>
9
- </p>
10
- <p>
11
- <%= f.label :redirect_uri %><br />
9
+ </div>
10
+ <div>
11
+ <%= f.label :redirect_uri %>
12
12
  <%= f.text_field :redirect_uri %>
13
- </p>
14
- <p>
13
+ </div>
14
+ <div>
15
15
  <%= f.submit 'Update' %>
16
- </p>
16
+ </div>
17
17
  <% end %>
18
18
 
19
- <%= link_to 'Show', @oauth_client %> |
20
- <%= link_to 'Back', oauth_clients_path %>
19
+ <%= link_to 'Show', @oauth_client, :class => 'show_link' %> |
20
+ <%= link_to 'Back', oauth_clients_path, :class => 'back_link' %>
@@ -1,11 +1,12 @@
1
1
  <h1>Listing oauth_clients</h1>
2
2
 
3
- <table>
3
+ <table id="oauth_clients_table" class="list_table">
4
4
  <tr>
5
5
  <th>Name</th>
6
6
  <th>Client id</th>
7
7
  <th>Client secret</th>
8
8
  <th>Redirect URI</th>
9
+ <th>Actions</th>
9
10
  </tr>
10
11
 
11
12
  <% @oauth_clients.each do |oauth_client| %>
@@ -14,13 +15,14 @@
14
15
  <td><%=h oauth_client.client_id %></td>
15
16
  <td><%=h oauth_client.client_secret %></td>
16
17
  <td><%=h oauth_client.redirect_uri %></td>
17
- <td><%= link_to 'Show', oauth_client %></td>
18
- <td><%= link_to 'Edit', edit_oauth_client_path(oauth_client) %></td>
19
- <td><%= link_to 'Destroy', oauth_client, :confirm => 'Are you sure?', :method => :delete %></td>
18
+ <td>
19
+ <%= link_to 'Edit', edit_oauth_client_path(oauth_client), :class => 'edit_link' %>
20
+ <%= link_to 'Destroy', oauth_client, :confirm => 'Are you sure?', :method => :delete, :class => 'delete_link' %>
21
+ </td>
20
22
  </tr>
21
23
  <% end %>
22
24
  </table>
23
25
 
24
26
  <br />
25
27
 
26
- <%= link_to 'New oauth_client', new_oauth_client_path %>
28
+ <%= link_to 'New oauth_client', new_oauth_client_path, :class => 'link_as_button', :id => 'new_oauth_client_button' %>
@@ -1,19 +1,21 @@
1
1
  <h1>New oauth_client</h1>
2
2
 
3
- <% form_for(@oauth_client) do |f| %>
3
+ <!-- add in an ID for the form -->
4
+
5
+ <% form_for(@oauth_client, :html => {:id => 'oauth_client_create_form', :class => nil}) do |f| %>
4
6
  <%= f.error_messages %>
5
7
 
6
- <p>
7
- <%= f.label :name %><br />
8
+ <div>
9
+ <%= f.label :name %>
8
10
  <%= f.text_field :name %>
9
- </p>
10
- <p>
11
- <%= f.label :redirect_uri %><br />
11
+ </div>
12
+ <div>
13
+ <%= f.label :redirect_uri %>
12
14
  <%= f.text_field :redirect_uri %>
13
- </p>
14
- <p>
15
+ </div>
16
+ <div>
15
17
  <%= f.submit 'Create' %>
16
- </p>
18
+ </div>
17
19
  <% end %>
18
20
 
19
- <%= link_to 'Back', oauth_clients_path %>
21
+ <%= link_to 'Back', oauth_clients_path, :class => 'back_link' %>
@@ -1,4 +1,4 @@
1
- <table>
1
+ <table id="oauth_user_token_table" class="list_table">
2
2
  <tr>
3
3
  <th>Client</th>
4
4
  <th>Token</th>
@@ -8,7 +8,7 @@
8
8
  <tr>
9
9
  <td><%= token.oauth_client.name %></td>
10
10
  <td><%= token.access_token %></td>
11
- <td><%= link_to('Destroy', {:action => :revoke, :token_id => token.id, :controller => 'Oauth2::Provider::OauthUserTokens'}, {:confirm => 'Are you sure?', :method => :delete})%></td>
11
+ <td><%= link_to('Destroy', {:action => :revoke, :token_id => token.id, :controller => 'Oauth2::Provider::OauthUserTokens'}, {:confirm => 'Are you sure?', :method => :delete, :class => 'delete_link'})%></td>
12
12
  </tr>
13
13
  <% end -%>
14
14
  </table>
data/config/routes.rb CHANGED
@@ -2,13 +2,18 @@
2
2
  # Licenced under the MIT License (http://www.opensource.org/licenses/mit-license.php)
3
3
 
4
4
  ActionController::Routing::Routes.draw do |map|
5
-
6
- map.resources :oauth_clients, :controller => 'Oauth2::Provider::OauthClients', :as => 'oauth/clients'
7
-
8
- map.connect '/oauth/authorize', :controller => 'Oauth2::Provider::OauthAuthorize', :action => :authorize, :conditions => {:method => :post}
9
- map.connect '/oauth/authorize', :controller => 'Oauth2::Provider::OauthAuthorize', :action => :index, :conditions => {:method => :get}
10
- map.connect '/oauth/token', :controller => 'Oauth2::Provider::OauthToken', :action => :get_token, :conditions => {:method => :post}
11
-
12
- map.connect '/oauth/user_tokens/revoke/:token_id', :controller => 'Oauth2::Provider::OauthUserTokens', :action => :revoke, :conditions => {:method => :delete}
13
- map.connect '/oauth/user_tokens', :controller => 'Oauth2::Provider::OauthUserTokens', :action => :index, :conditions => {:method => :get}
5
+
6
+ admin_prefix=ENV['ADMIN_OAUTH_URL_PREFIX']
7
+
8
+ map.resources :oauth_clients, :controller => 'Oauth2::Provider::OauthClients', :as => "#{admin_prefix}oauth/clients"
9
+
10
+ user_prefix=ENV['USER_OAUTH_URL_PREFIX']
11
+
12
+ map.connect "#{user_prefix}/oauth/authorize", :controller => 'Oauth2::Provider::OauthAuthorize', :action => :authorize, :conditions => {:method => :post}
13
+ map.connect "#{user_prefix}/oauth/authorize", :controller => 'Oauth2::Provider::OauthAuthorize', :action => :index, :conditions => {:method => :get}
14
+ map.connect "#{user_prefix}/oauth/token", :controller => 'Oauth2::Provider::OauthToken', :action => :get_token, :conditions => {:method => :post}
15
+
16
+ map.connect "#{user_prefix}/oauth/user_tokens/revoke/:token_id", :controller => 'Oauth2::Provider::OauthUserTokens', :action => :revoke, :conditions => {:method => :delete}
17
+ map.connect "#{user_prefix}/oauth/user_tokens", :controller => 'Oauth2::Provider::OauthUserTokens', :action => :index, :conditions => {:method => :get}
18
+
14
19
  end
@@ -7,7 +7,7 @@ class CreateOauthAuthorizations < ActiveRecord::Migration
7
7
  t.string :user_id
8
8
  t.integer :oauth_client_id
9
9
  t.string :code
10
- t.timestamp :expires_at
10
+ t.integer :expires_at
11
11
 
12
12
  t.timestamps
13
13
  end
@@ -8,7 +8,7 @@ class CreateOauthTokens < ActiveRecord::Migration
8
8
  t.integer :oauth_client_id
9
9
  t.string :access_token
10
10
  t.string :refresh_token
11
- t.timestamp :expires_at
11
+ t.integer :expires_at
12
12
 
13
13
  t.timestamps
14
14
  end
data/init.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2010 ThoughtWorks Inc. (http://thoughtworks.com)
2
2
  # Licenced under the MIT License (http://www.opensource.org/licenses/mit-license.php)
3
3
 
4
- # DO NOT REMOVE
5
- # this file is required when this plugin is used as a plugin!
4
+ # !!perform any initialization in oauth2_provider!!
5
+ require 'oauth2_provider'
@@ -0,0 +1,108 @@
1
+ # Copyright (c) 2010 ThoughtWorks Inc. (http://thoughtworks.com)
2
+ # Licenced under the MIT License (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ if defined?(ActiveRecord)
5
+ module Oauth2
6
+ module Provider
7
+ class ARDatasource
8
+
9
+ class OauthClientDto < ActiveRecord::Base
10
+ set_table_name :oauth_clients
11
+ end
12
+
13
+ class OauthAuthorizationDto < ActiveRecord::Base
14
+ set_table_name :oauth_authorizations
15
+ end
16
+
17
+ class OauthTokenDto < ActiveRecord::Base
18
+ set_table_name :oauth_tokens
19
+ end
20
+
21
+ # used in tests, use it to clear datasource
22
+ def reset
23
+
24
+ end
25
+
26
+ def find_oauth_client_by_id(id)
27
+ OauthClientDto.find_by_id(id)
28
+ end
29
+
30
+ def find_oauth_client_by_client_id(client_id)
31
+ OauthClientDto.find_by_client_id(client_id)
32
+ end
33
+
34
+ def find_all_oauth_client
35
+ OauthClientDto.all
36
+ end
37
+
38
+ def save_oauth_client(attrs)
39
+ save(OauthClientDto, attrs)
40
+ end
41
+
42
+ def delete_oauth_client(id)
43
+ OauthClientDto.delete(id)
44
+ end
45
+
46
+ def find_all_oauth_authorization_by_oauth_client_id(client_id)
47
+ OauthAuthorizationDto.find_all_by_oauth_client_id(client_id)
48
+ end
49
+
50
+ def find_oauth_authorization_by_id(id)
51
+ OauthAuthorizationDto.find_by_id(id)
52
+ end
53
+
54
+ def find_oauth_authorization_by_code(code)
55
+ OauthAuthorizationDto.find_by_code(code)
56
+ end
57
+
58
+ def save_oauth_authorization(attrs)
59
+ save(OauthAuthorizationDto, attrs)
60
+ end
61
+
62
+ def delete_oauth_authorization(id)
63
+ OauthAuthorizationDto.delete(id)
64
+ end
65
+
66
+ def find_oauth_token_by_id(id)
67
+ OauthTokenDto.find_by_id(id)
68
+ end
69
+
70
+ def find_all_oauth_token_by_oauth_client_id(client_id)
71
+ OauthTokenDto.find_all_by_oauth_client_id(client_id)
72
+ end
73
+
74
+ def find_all_oauth_token_by_user_id(user_id)
75
+ OauthTokenDto.find_all_by_user_id(user_id)
76
+ end
77
+
78
+ def find_oauth_token_by_access_token(access_token)
79
+ OauthTokenDto.find_by_access_token(access_token)
80
+ end
81
+
82
+ def find_oauth_token_by_refresh_token(refresh_token)
83
+ OauthTokenDto.find_by_refresh_token(refresh_token)
84
+ end
85
+
86
+ def save_oauth_token(attrs)
87
+ save(OauthTokenDto, attrs)
88
+ end
89
+
90
+ def delete_oauth_token(id)
91
+ OauthTokenDto.delete(id)
92
+ end
93
+
94
+ private
95
+
96
+ def save(dto_klass, attrs)
97
+ dto = dto_klass.find_by_id(attrs[:id])
98
+ if dto
99
+ dto.update_attributes(attrs)
100
+ else
101
+ dto = dto_klass.create(attrs)
102
+ end
103
+ dto
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -29,8 +29,8 @@ module Oauth2
29
29
  header_field = request.headers["Authorization"]
30
30
 
31
31
  if header_field =~ /Token token="(.*)"/
32
- token = OauthToken.find_by_access_token($1)
33
- token.user_id if token
32
+ token = OauthToken.find_one(:access_token, $1)
33
+ token.user_id if (token && !token.expired?)
34
34
  end
35
35
  end
36
36
 
@@ -0,0 +1,121 @@
1
+ # Copyright (c) 2010 ThoughtWorks Inc. (http://thoughtworks.com)
2
+ # Licenced under the MIT License (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ require 'ostruct'
5
+ module Oauth2
6
+ module Provider
7
+ class InMemoryDatasource
8
+
9
+ class MyStruct < OpenStruct
10
+
11
+ attr_accessor :id
12
+
13
+ def initialize(id, attrs)
14
+ self.id = id
15
+ super(attrs)
16
+ end
17
+ end
18
+
19
+ @@id = 0
20
+
21
+ @@oauth_clients = []
22
+ @@oauth_tokens = []
23
+ @@oauth_authorizations = []
24
+
25
+ def reset
26
+ @@id = 0
27
+ @@oauth_clients = []
28
+ @@oauth_tokens = []
29
+ @@oauth_authorizations = []
30
+ end
31
+
32
+ def find_oauth_client_by_id(id)
33
+ @@oauth_clients.find{|i| i.id.to_s == id.to_s}
34
+ end
35
+
36
+ def find_oauth_client_by_client_id(client_id)
37
+ @@oauth_clients.find{|i| i.client_id.to_s == client_id.to_s}
38
+ end
39
+
40
+ def find_all_oauth_client
41
+ @@oauth_clients
42
+ end
43
+
44
+ def save_oauth_client(attrs)
45
+ save(@@oauth_clients, attrs)
46
+ end
47
+
48
+ def delete_oauth_client(id)
49
+ @@oauth_clients.delete_if {|i| i.id.to_s == id.to_s}
50
+ end
51
+
52
+ def find_all_oauth_authorization_by_oauth_client_id(client_id)
53
+ @@oauth_authorizations.select {|i| i.oauth_client_id.to_s == client_id.to_s}
54
+ end
55
+
56
+ def find_oauth_authorization_by_id(id)
57
+ @@oauth_authorizations.find{|i| i.id.to_s == id.to_s}
58
+ end
59
+
60
+ def find_oauth_authorization_by_code(code)
61
+ @@oauth_authorizations.find{|i| i.code.to_s == code.to_s}
62
+ end
63
+
64
+ def save_oauth_authorization(attrs)
65
+ save(@@oauth_authorizations, attrs)
66
+ end
67
+
68
+ def delete_oauth_authorization(id)
69
+ @@oauth_authorizations.delete_if {|i| i.id.to_s == id.to_s}
70
+ end
71
+
72
+ def find_oauth_token_by_id(id)
73
+ @@oauth_tokens.find{|i| i.id.to_s == id.to_s}
74
+ end
75
+
76
+ def find_all_oauth_token_by_oauth_client_id(client_id)
77
+ @@oauth_tokens.select {|i| i.oauth_client_id.to_s == client_id.to_s}
78
+ end
79
+
80
+ def find_all_oauth_token_by_user_id(user_id)
81
+ @@oauth_tokens.select {|i| i.user_id.to_s == user_id.to_s}
82
+ end
83
+
84
+ def find_oauth_token_by_access_token(access_token)
85
+ @@oauth_tokens.find {|i| i.access_token.to_s == access_token.to_s}
86
+ end
87
+
88
+ def find_oauth_token_by_refresh_token(refresh_token)
89
+ @@oauth_tokens.find {|i| i.refresh_token.to_s == refresh_token.to_s}
90
+ end
91
+
92
+ def save_oauth_token(attrs)
93
+ save(@@oauth_tokens, attrs)
94
+ end
95
+
96
+ def delete_oauth_token(id)
97
+ @@oauth_tokens.delete_if { |i| i.id.to_s == id .to_s}
98
+ end
99
+
100
+ private
101
+ def save(collection, attrs)
102
+ dto = collection.find {|i| i.id.to_s == attrs[:id].to_s}
103
+
104
+ if dto
105
+ attrs.each do |k, v|
106
+ dto.send("#{k}=", v)
107
+ end
108
+ else
109
+ dto = MyStruct.new(next_id, attrs)
110
+ collection << dto
111
+ end
112
+ dto
113
+ end
114
+
115
+ def next_id
116
+ @@id += 1
117
+ @@id.to_s
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,204 @@
1
+ # Copyright (c) 2010 ThoughtWorks Inc. (http://thoughtworks.com)
2
+ # Licenced under the MIT License (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ module Oauth2
5
+ module Provider
6
+ class NotFoundException < StandardError
7
+ end
8
+
9
+ class RecordNotSaved < StandardError
10
+ end
11
+
12
+ class ModelBase
13
+ include Validatable
14
+ CONVERTORS = {
15
+ :integer => Proc.new { |v| v.to_i },
16
+ :string => Proc.new { |v| v.to_s }
17
+ }.with_indifferent_access
18
+
19
+ class_inheritable_hash :db_columns
20
+ self.db_columns = {}
21
+
22
+ def self.columns(*names)
23
+ names.each do |name|
24
+ column_name, convertor = (Hash === name) ?
25
+ [name.keys.first, CONVERTORS[name.values.first]] :
26
+ [name, CONVERTORS[:string]]
27
+ attr_accessor column_name
28
+ self.db_columns[column_name.to_s] = convertor
29
+ end
30
+ end
31
+
32
+ columns :id
33
+
34
+ def initialize(attributes={})
35
+ assign_attributes(attributes)
36
+ end
37
+
38
+ cattr_accessor :datasource
39
+
40
+ def self.datasource=(ds)
41
+ @@datasource = case ds
42
+ when NilClass
43
+ default_datasource
44
+ when String
45
+ eval(ds).new
46
+ when Class
47
+ ds.new
48
+ else
49
+ ds
50
+ end
51
+ end
52
+
53
+ def self.datasource
54
+ @@datasource ||= default_datasource
55
+ end
56
+
57
+ def datasource
58
+ self.class.datasource
59
+ end
60
+
61
+ def self.default_datasource
62
+ if defined?(ActiveRecord)
63
+ ARDatasource.new
64
+ else
65
+ unless ENV['LOAD_OAUTH_SILENTLY']
66
+ puts "*"*80
67
+ puts "*** Activerecord is not defined! Using InMemoryDatasource, which will not persist across application restarts!! ***"
68
+ puts "*"*80
69
+ end
70
+ InMemoryDatasource.new
71
+ end
72
+ end
73
+
74
+ def self.find(id)
75
+ find_by_id(id) || raise(NotFoundException.new("Record not found!"))
76
+ end
77
+
78
+ def self.find_by_id(id)
79
+ find_one(:id, id)
80
+ end
81
+
82
+ def self.find_all_with(column_name, column_value)
83
+ datasource.send("find_all_#{compact_name}_by_#{column_name}", convert(column_name, column_value)).collect do |dto|
84
+ new.update_from_dto(dto)
85
+ end
86
+ end
87
+
88
+ def self.find_one(column_name, column_value)
89
+ if dto = datasource.send("find_#{compact_name}_by_#{column_name}", convert(column_name, column_value))
90
+ self.new.update_from_dto(dto)
91
+ end
92
+ end
93
+
94
+ def self.all
95
+ datasource.send("find_all_#{compact_name}").collect do |dto|
96
+ new.update_from_dto(dto)
97
+ end
98
+ end
99
+
100
+ def self.count
101
+ all.size
102
+ end
103
+
104
+ def self.size
105
+ all.size
106
+ end
107
+
108
+ def self.compact_name
109
+ self.name.split('::').last.underscore
110
+ end
111
+
112
+ def self.create(attributes={})
113
+ client = self.new(attributes)
114
+ client.save
115
+ client
116
+ end
117
+
118
+ def self.create!(attributes={})
119
+ client = self.new(attributes)
120
+ client.save!
121
+ client
122
+ end
123
+
124
+ def update_attributes(attributes={})
125
+ assign_attributes(attributes)
126
+ save
127
+ end
128
+
129
+ def save!
130
+ save || raise(RecordNotSaved.new("Could not save model!"))
131
+ end
132
+
133
+ def save
134
+ before_create if new_record?
135
+ attrs = db_columns.keys.inject({}) do |result, column_name|
136
+ result[column_name] = read_attribute(column_name)
137
+ result
138
+ end
139
+
140
+ if self.valid?
141
+ dto = datasource.send("save_#{self.class.compact_name}", attrs.with_indifferent_access)
142
+ update_from_dto(dto)
143
+ return true
144
+ end
145
+ false
146
+ end
147
+
148
+ def reload
149
+ update_from_dto(self.class.find(id))
150
+ end
151
+
152
+ def destroy
153
+ before_destroy
154
+ datasource.send("delete_#{self.class.compact_name}", convert(:id, id) )
155
+ end
156
+
157
+ def before_create
158
+ # for subclasses to override to support hooks.
159
+ end
160
+
161
+ def before_destroy
162
+ # for subclasses to override to support hooks.
163
+ end
164
+
165
+ def update_from_dto(dto)
166
+ db_columns.keys.each do |column_name|
167
+ write_attribute(column_name, dto.send(column_name))
168
+ end
169
+ self
170
+ end
171
+
172
+ def new_record?
173
+ id.nil?
174
+ end
175
+
176
+ def to_param
177
+ id.nil? ? nil: id.to_s
178
+ end
179
+
180
+ def assign_attributes(attrs={})
181
+ attrs.each { |k, v| write_attribute(k, v) }
182
+ end
183
+
184
+ private
185
+
186
+ def self.convert(column_name, value)
187
+ db_columns[column_name.to_s].call(value)
188
+ end
189
+
190
+ def convert(column_name, value)
191
+ self.class.convert(column_name, value)
192
+ end
193
+
194
+ def read_attribute(column_name)
195
+ convert(column_name, self.send(column_name))
196
+ end
197
+
198
+ def write_attribute(column_name, value)
199
+ self.send("#{column_name}=", convert(column_name, value))
200
+ end
201
+
202
+ end
203
+ end
204
+ end
@@ -1,5 +1,20 @@
1
1
  # Copyright (c) 2010 ThoughtWorks Inc. (http://thoughtworks.com)
2
2
  # Licenced under the MIT License (http://www.opensource.org/licenses/mit-license.php)
3
3
 
4
- # DO NOT REMOVE
5
- # this file is required when this plugin is used as a gem!
4
+ require 'oauth2/provider/a_r_datasource'
5
+ require 'oauth2/provider/in_memory_datasource'
6
+ require 'oauth2/provider/model_base'
7
+ require 'oauth2/provider/clock'
8
+
9
+ Oauth2::Provider::ModelBase.datasource = ENV["OAUTH2_PROVIDER_DATASOURCE"]
10
+
11
+ unless ENV['LOAD_OAUTH_SILENTLY']
12
+ puts "*"*80
13
+ puts "*** Using data source: #{Oauth2::Provider::ModelBase.datasource.class}"
14
+ puts "*"*80
15
+ end
16
+
17
+ Dir[File.join(File.dirname(__FILE__), "..", "app", "**", '*.rb')].each do |rb_file|
18
+ require File.expand_path(rb_file)
19
+ end
20
+
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{oauth2_provider}
5
- s.version = "0.1.0"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["ThoughtWorks, Inc."]
9
- s.date = %q{2010-07-23}
9
+ s.date = %q{2010-08-31}
10
10
  s.description = %q{A Rails plugin to OAuth v2.0 enable your rails application. This plugin implements v09 of the OAuth2 draft spec http://tools.ietf.org/html/draft-ietf-oauth-v2-09.}
11
11
  s.email = %q{ketan@thoughtworks.com}
12
12
  s.extra_rdoc_files = ["README.textile", "MIT-LICENSE.txt"]
13
- s.files = ["app/controllers/oauth2/provider/oauth_authorize_controller.rb", "app/controllers/oauth2/provider/oauth_clients_controller.rb", "app/controllers/oauth2/provider/oauth_token_controller.rb", "app/controllers/oauth2/provider/oauth_user_tokens_controller.rb", "app/models/oauth2/provider/oauth_authorization.rb", "app/models/oauth2/provider/oauth_client.rb", "app/models/oauth2/provider/oauth_token.rb", "app/views/oauth2/provider/layouts/oauth_clients.html.erb", "app/views/oauth2/provider/oauth_authorize/index.html.erb", "app/views/oauth2/provider/oauth_clients/edit.html.erb", "app/views/oauth2/provider/oauth_clients/index.html.erb", "app/views/oauth2/provider/oauth_clients/new.html.erb", "app/views/oauth2/provider/oauth_clients/show.html.erb", "app/views/oauth2/provider/oauth_user_tokens/index.html.erb", "config/routes.rb", "generators/oauth2_provider/oauth2_provider_generator.rb", "generators/oauth2_provider/templates/config/initializers/oauth2_provider.rb", "generators/oauth2_provider/templates/db/migrate/create_oauth_authorizations.rb", "generators/oauth2_provider/templates/db/migrate/create_oauth_clients.rb", "generators/oauth2_provider/templates/db/migrate/create_oauth_tokens.rb", "init.rb", "lib/oauth2/provider/application_controller_methods.rb", "lib/oauth2/provider/clock.rb", "lib/oauth2_provider.rb", "MIT-LICENSE.txt", "oauth2_provider.gemspec", "README.textile", "tasks/gem.rake", "CHANGELOG"]
13
+ s.files = ["app/controllers/oauth2/provider/oauth_authorize_controller.rb", "app/controllers/oauth2/provider/oauth_clients_controller.rb", "app/controllers/oauth2/provider/oauth_token_controller.rb", "app/controllers/oauth2/provider/oauth_user_tokens_controller.rb", "app/models/oauth2/provider/oauth_authorization.rb", "app/models/oauth2/provider/oauth_client.rb", "app/models/oauth2/provider/oauth_token.rb", "app/views/oauth2/provider/layouts/oauth_clients.html.erb", "app/views/oauth2/provider/oauth_authorize/index.html.erb", "app/views/oauth2/provider/oauth_clients/edit.html.erb", "app/views/oauth2/provider/oauth_clients/index.html.erb", "app/views/oauth2/provider/oauth_clients/new.html.erb", "app/views/oauth2/provider/oauth_clients/show.html.erb", "app/views/oauth2/provider/oauth_user_tokens/index.html.erb", "config/routes.rb", "generators/oauth2_provider/oauth2_provider_generator.rb", "generators/oauth2_provider/templates/config/initializers/oauth2_provider.rb", "generators/oauth2_provider/templates/db/migrate/create_oauth_authorizations.rb", "generators/oauth2_provider/templates/db/migrate/create_oauth_clients.rb", "generators/oauth2_provider/templates/db/migrate/create_oauth_tokens.rb", "init.rb", "lib/oauth2/provider/a_r_datasource.rb", "lib/oauth2/provider/application_controller_methods.rb", "lib/oauth2/provider/clock.rb", "lib/oauth2/provider/in_memory_datasource.rb", "lib/oauth2/provider/model_base.rb", "lib/oauth2_provider.rb", "MIT-LICENSE.txt", "oauth2_provider.gemspec", "README.textile", "tasks/gem.rake", "CHANGELOG"]
14
14
  s.homepage = %q{http://github.com/ThoughtWorksStudios/oauth2_provider}
15
15
  s.require_paths = ["lib"]
16
16
  s.rubygems_version = %q{1.3.7}
data/tasks/gem.rake CHANGED
@@ -35,7 +35,7 @@ namespace :release do
35
35
 
36
36
  spec = Gem::Specification.new do |s|
37
37
  s.name = "oauth2_provider"
38
- s.version = "0.1.0"
38
+ s.version = "0.2.0"
39
39
  s.author = "ThoughtWorks, Inc."
40
40
  s.email = "ketan@thoughtworks.com"
41
41
  s.homepage = "http://github.com/ThoughtWorksStudios/oauth2_provider"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oauth2_provider
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - ThoughtWorks, Inc.
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-23 00:00:00 -07:00
18
+ date: 2010-08-31 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -50,8 +50,11 @@ files:
50
50
  - generators/oauth2_provider/templates/db/migrate/create_oauth_clients.rb
51
51
  - generators/oauth2_provider/templates/db/migrate/create_oauth_tokens.rb
52
52
  - init.rb
53
+ - lib/oauth2/provider/a_r_datasource.rb
53
54
  - lib/oauth2/provider/application_controller_methods.rb
54
55
  - lib/oauth2/provider/clock.rb
56
+ - lib/oauth2/provider/in_memory_datasource.rb
57
+ - lib/oauth2/provider/model_base.rb
55
58
  - lib/oauth2_provider.rb
56
59
  - MIT-LICENSE.txt
57
60
  - oauth2_provider.gemspec