opro 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/Gemfile +6 -2
  2. data/Gemfile.lock +37 -33
  3. data/README.md +60 -31
  4. data/Rakefile +8 -0
  5. data/VERSION +1 -1
  6. data/app/controllers/oauth/auth_controller.rb +35 -36
  7. data/app/controllers/oauth/client_app_controller.rb +24 -0
  8. data/app/controllers/oauth/docs_controller.rb +1 -1
  9. data/app/controllers/oauth/tests_controller.rb +4 -26
  10. data/app/controllers/oauth/token_controller.rb +40 -0
  11. data/app/controllers/opro_controller.rb +4 -0
  12. data/app/models/oauth/access_grant.rb +47 -14
  13. data/app/models/oauth/{client_application.rb → client_appl.rb} +1 -1
  14. data/app/views/oauth/{client_application → client_app}/create.html.erb +1 -1
  15. data/app/views/oauth/{client_application → client_app}/index.html.erb +1 -1
  16. data/app/views/oauth/{client_application → client_app}/new.html.erb +1 -1
  17. data/app/views/oauth/docs/index.html.erb +8 -0
  18. data/app/views/oauth/docs/markdown/oauth.md.erb +2 -2
  19. data/app/views/oauth/docs/markdown/permissions.md.erb +30 -0
  20. data/app/views/oauth/docs/markdown/quick_start.md.erb +1 -1
  21. data/app/views/oauth/docs/markdown/refresh_tokens.md.erb +18 -0
  22. data/config/routes.rb +5 -10
  23. data/lib/generators/active_record/opro_generator.rb +1 -1
  24. data/lib/generators/active_record/templates/access_grants.rb +1 -1
  25. data/lib/generators/active_record/templates/client_applications.rb +1 -1
  26. data/lib/generators/opro/install_generator.rb +5 -0
  27. data/lib/generators/templates/opro.rb +10 -3
  28. data/lib/opro.rb +7 -1
  29. data/lib/opro/controllers/application_controller_helper.rb +7 -2
  30. data/lib/opro/engine.rb +4 -0
  31. data/lib/opro/rails/routes.rb +17 -0
  32. data/opro.gemspec +27 -15
  33. data/test/controllers/refresh_token_test.rb +0 -0
  34. data/test/dummy/config/environments/test.rb +4 -0
  35. data/test/dummy/config/initializers/opro.rb +10 -3
  36. data/test/dummy/config/routes.rb +2 -0
  37. data/test/dummy/db/migrate/20120514060322_create_opro_access_grants.rb +1 -1
  38. data/test/dummy/db/migrate/20120514060323_create_opro_client_applications.rb +1 -1
  39. data/test/integration/action_dispatch/auth_controller_test.rb +64 -0
  40. data/test/integration/action_dispatch/oauth_flow_test.rb +34 -0
  41. data/test/integration/action_dispatch/refresh_token_test.rb +54 -0
  42. data/test/integration/auth_controller_test.rb +8 -7
  43. data/test/integration/client_app_controller_test.rb +24 -0
  44. data/test/integration/docs_controller_test.rb +9 -1
  45. data/test/integration/oauth_test.rb +1 -4
  46. data/test/integration/refresh_token_test.rb +32 -0
  47. data/test/support/integration_case.rb +10 -1
  48. data/test/test_helper.rb +7 -3
  49. metadata +56 -36
  50. data/app/controllers/oauth/client_application_controller.rb +0 -21
  51. data/app/controllers/opro_application_controller.rb +0 -8
  52. data/test/integration/client_application_controller_test.rb +0 -24
@@ -15,6 +15,7 @@ module Opro
15
15
 
16
16
  def opro_authenticate_user!
17
17
  Opro.authenticate_user_method.call(self)
18
+ true
18
19
  end
19
20
 
20
21
  module ClassMethods
@@ -37,7 +38,11 @@ module Opro
37
38
 
38
39
  # returns boolean if oauth request
39
40
  def valid_oauth?
40
- oauth? && oauth_user.present? && oauth_client_has_permissions?
41
+ oauth? && oauth_user.present? && oauth_client_not_expired? && oauth_client_has_permissions?
42
+ end
43
+
44
+ def oauth_client_not_expired?
45
+ oauth_access_grant.not_expired?
41
46
  end
42
47
 
43
48
  def disallow_oauth
@@ -53,7 +58,7 @@ module Opro
53
58
  end
54
59
 
55
60
  def oauth_access_grant
56
- @oauth_access_grant ||= Oauth::AccessGrant.find_for_token(params[:access_token])
61
+ @oauth_access_grant ||= Oauth::AuthGrant.find_for_token(params[:access_token])
57
62
  end
58
63
 
59
64
  def oauth_client_app
data/lib/opro/engine.rb CHANGED
@@ -1,5 +1,9 @@
1
+ require 'opro/rails/routes'
2
+
1
3
  module Opro
2
4
  class Engine < Rails::Engine
5
+ isolate_namespace Opro
6
+
3
7
 
4
8
  initializer "opro.include_helpers" do
5
9
  Opro.include_helpers(Opro::Controllers)
@@ -0,0 +1,17 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+ # Includes mount_opro_oauth method for routes. This method is responsible to
4
+ # generate all needed routes for oauth
5
+ def mount_opro_oauth(options = {})
6
+ skip_routes = options[:except].is_a?(Array) ? options[:except] : [options[:except]]
7
+
8
+ match 'oauth/new' => 'oauth/auth#new', :as => 'oauth_new'
9
+ match 'oauth/authorize' => 'oauth/auth#create', :as => 'oauth_authorize'
10
+ match 'oauth/token' => 'oauth/token#create', :as => 'oauth_token'
11
+
12
+ resources :oauth_docs, :controller => 'oauth/docs' unless skip_routes.include?(:docs)
13
+ resources :oauth_tests, :controller => 'oauth/tests' unless skip_routes.include?(:tests)
14
+ resources :oauth_client_apps, :controller => 'oauth/client_app' unless skip_routes.include?(:client_apps)
15
+ end
16
+ end
17
+ end
data/opro.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "opro"
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["schneems"]
12
- s.date = "2012-06-14"
12
+ s.date = "2012-06-18"
13
13
  s.description = " Enable OAuth clients (iphone, android, web sites, etc.) to access and use your Rails application, what you do with it is up to you"
14
14
  s.email = "richard.schneeman@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -24,20 +24,23 @@ Gem::Specification.new do |s|
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "app/controllers/oauth/auth_controller.rb",
27
- "app/controllers/oauth/client_application_controller.rb",
27
+ "app/controllers/oauth/client_app_controller.rb",
28
28
  "app/controllers/oauth/docs_controller.rb",
29
29
  "app/controllers/oauth/tests_controller.rb",
30
- "app/controllers/opro_application_controller.rb",
30
+ "app/controllers/oauth/token_controller.rb",
31
+ "app/controllers/opro_controller.rb",
31
32
  "app/models/oauth/access_grant.rb",
32
- "app/models/oauth/client_application.rb",
33
+ "app/models/oauth/client_appl.rb",
33
34
  "app/views/oauth/auth/new.html.erb",
34
- "app/views/oauth/client_application/create.html.erb",
35
- "app/views/oauth/client_application/index.html.erb",
36
- "app/views/oauth/client_application/new.html.erb",
35
+ "app/views/oauth/client_app/create.html.erb",
36
+ "app/views/oauth/client_app/index.html.erb",
37
+ "app/views/oauth/client_app/new.html.erb",
37
38
  "app/views/oauth/docs/index.html.erb",
38
39
  "app/views/oauth/docs/markdown/curl.md.erb",
39
40
  "app/views/oauth/docs/markdown/oauth.md.erb",
41
+ "app/views/oauth/docs/markdown/permissions.md.erb",
40
42
  "app/views/oauth/docs/markdown/quick_start.md.erb",
43
+ "app/views/oauth/docs/markdown/refresh_tokens.md.erb",
41
44
  "app/views/oauth/docs/show.html.erb",
42
45
  "app/views/oauth/tests/index.html.erb",
43
46
  "config/routes.rb",
@@ -51,8 +54,10 @@ Gem::Specification.new do |s|
51
54
  "lib/opro/controllers/concerns/error_messages.rb",
52
55
  "lib/opro/controllers/concerns/permissions.rb",
53
56
  "lib/opro/engine.rb",
57
+ "lib/opro/rails/routes.rb",
54
58
  "opro.gemspec",
55
59
  "test/controllers/permissions_test.rb",
60
+ "test/controllers/refresh_token_test.rb",
56
61
  "test/dummy/Rakefile",
57
62
  "test/dummy/app/controllers/application_controller.rb",
58
63
  "test/dummy/app/controllers/pages_controller.rb",
@@ -96,10 +101,14 @@ Gem::Specification.new do |s|
96
101
  "test/dummy/public/javascripts/rails.js",
97
102
  "test/dummy/public/stylesheets/.gitkeep",
98
103
  "test/dummy/script/rails",
104
+ "test/integration/action_dispatch/auth_controller_test.rb",
105
+ "test/integration/action_dispatch/oauth_flow_test.rb",
106
+ "test/integration/action_dispatch/refresh_token_test.rb",
99
107
  "test/integration/auth_controller_test.rb",
100
- "test/integration/client_application_controller_test.rb",
108
+ "test/integration/client_app_controller_test.rb",
101
109
  "test/integration/docs_controller_test.rb",
102
110
  "test/integration/oauth_test.rb",
111
+ "test/integration/refresh_token_test.rb",
103
112
  "test/opro_test.rb",
104
113
  "test/support/integration_case.rb",
105
114
  "test/test_helper.rb"
@@ -114,10 +123,11 @@ Gem::Specification.new do |s|
114
123
  s.specification_version = 3
115
124
 
116
125
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
117
- s.add_runtime_dependency(%q<activesupport>, [">= 3.0.7"])
118
- s.add_runtime_dependency(%q<rails>, [">= 3.0.7"])
126
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.1.0"])
127
+ s.add_runtime_dependency(%q<rails>, [">= 3.1.0"])
119
128
  s.add_runtime_dependency(%q<bluecloth>, [">= 0"])
120
129
  s.add_development_dependency(%q<mocha>, [">= 0"])
130
+ s.add_development_dependency(%q<timecop>, [">= 0"])
121
131
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
122
132
  s.add_development_dependency(%q<bundler>, [">= 1.1.3"])
123
133
  s.add_development_dependency(%q<capybara>, [">= 0.4.0"])
@@ -127,10 +137,11 @@ Gem::Specification.new do |s|
127
137
  s.add_development_dependency(%q<rcov>, [">= 0"])
128
138
  s.add_development_dependency(%q<simplecov>, [">= 0"])
129
139
  else
130
- s.add_dependency(%q<activesupport>, [">= 3.0.7"])
131
- s.add_dependency(%q<rails>, [">= 3.0.7"])
140
+ s.add_dependency(%q<activesupport>, [">= 3.1.0"])
141
+ s.add_dependency(%q<rails>, [">= 3.1.0"])
132
142
  s.add_dependency(%q<bluecloth>, [">= 0"])
133
143
  s.add_dependency(%q<mocha>, [">= 0"])
144
+ s.add_dependency(%q<timecop>, [">= 0"])
134
145
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
135
146
  s.add_dependency(%q<bundler>, [">= 1.1.3"])
136
147
  s.add_dependency(%q<capybara>, [">= 0.4.0"])
@@ -141,10 +152,11 @@ Gem::Specification.new do |s|
141
152
  s.add_dependency(%q<simplecov>, [">= 0"])
142
153
  end
143
154
  else
144
- s.add_dependency(%q<activesupport>, [">= 3.0.7"])
145
- s.add_dependency(%q<rails>, [">= 3.0.7"])
155
+ s.add_dependency(%q<activesupport>, [">= 3.1.0"])
156
+ s.add_dependency(%q<rails>, [">= 3.1.0"])
146
157
  s.add_dependency(%q<bluecloth>, [">= 0"])
147
158
  s.add_dependency(%q<mocha>, [">= 0"])
159
+ s.add_dependency(%q<timecop>, [">= 0"])
148
160
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
149
161
  s.add_dependency(%q<bundler>, [">= 1.1.3"])
150
162
  s.add_dependency(%q<capybara>, [">= 0.4.0"])
File without changes
@@ -10,6 +10,10 @@ Dummy::Application.configure do
10
10
  # Log error messages when you accidentally call methods on nil.
11
11
  config.whiny_nils = true
12
12
 
13
+
14
+ config.log_level = :debug
15
+
16
+
13
17
  # Show full error reports and disable caching
14
18
  config.consider_all_requests_local = true
15
19
  config.action_controller.perform_caching = false
@@ -3,8 +3,15 @@ Opro.setup do |config|
3
3
  config.auth_strategy = :devise
4
4
 
5
5
  ## Add or remove application permissions
6
- # Read permission is turned on by default (any request with [GET])
7
- # Write permission is requestable by default (any request other than [GET])
8
- # Custom permissions can be configured by adding them to the request_permissions Array and configuring require_oauth_permissions in the controller
6
+ # Read permission (any request with [GET]) is turned on by default
7
+ # Write permission (any request other than [GET]) is requestable by default
8
+ # Custom permissions can be configured by adding them to `config.request_permissions`
9
+ # You can then require that permission on individual actions by calling
10
+ # `require_oauth_permissions` in the controller
9
11
  config.request_permissions = [:write]
12
+
13
+ ## Refresh Token config
14
+ # uncomment `config.require_refresh_within` to require refresh tokens
15
+ # this will expire tokens within the given time duration
16
+ # config.require_refresh_within = 1.month
10
17
  end
@@ -1,4 +1,6 @@
1
1
  Dummy::Application.routes.draw do
2
+ mount_opro_oauth
3
+
2
4
  devise_for :users
3
5
 
4
6
  resources :foo
@@ -1,4 +1,4 @@
1
- class CreateOproAccessGrants < ActiveRecord::Migration
1
+ class CreateOproAuthGrants < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :opro_access_grants do |t|
4
4
  t.string :code
@@ -1,4 +1,4 @@
1
- class CreateOproClientApplications < ActiveRecord::Migration
1
+ class CreateOproClientApps < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :opro_client_applications do |t|
4
4
  t.string :name
@@ -0,0 +1,64 @@
1
+ ## NOT CAPYBARA
2
+ # ActionDispatch::IntegrationTest
3
+ # http://guides.rubyonrails.org/testing.html#integration-testing
4
+ # used so we can test POST actions ^_^
5
+
6
+ require 'test_helper'
7
+
8
+ class AuthControllerTest < ActionDispatch::IntegrationTest
9
+ setup do
10
+ @user = create_user
11
+ @client_app = create_client_app
12
+ @redirect_uri = '/'
13
+ end
14
+
15
+
16
+ test "AUTHORIZE: previously authed user gets Authed immediately, permissions not changed" do
17
+ auth_grant = create_auth_grant_for_user(@user, @client_app)
18
+
19
+ params = { :client_id => @client_app.client_id ,
20
+ :client_secret => @client_app.client_secret,
21
+ :redirect_uri => @redirect_uri }
22
+
23
+ as_user(@user).post oauth_authorize_path(params)
24
+
25
+ assert_equal 302, status
26
+ follow_redirect!
27
+ assert_equal @redirect_uri, path
28
+ end
29
+
30
+
31
+ test "AUTHORIZE: app cannot force permissions change for previously authed user" do
32
+ auth_grant = create_auth_grant_for_user(@user, @client_app)
33
+ permissions = { 'foo' => 1 }
34
+ assert_not_equal auth_grant.permissions, permissions
35
+
36
+ params = { :client_id => @client_app.client_id ,
37
+ :client_secret => @client_app.client_secret,
38
+ :redirect_uri => @redirect_uri,
39
+ :permissions => permissions }
40
+
41
+ as_user(@user).post oauth_authorize_path(params)
42
+
43
+ assert_equal 302, status
44
+ follow_redirect!
45
+ assert_equal @redirect_uri, path
46
+ auth_grant = Oauth::AuthGrant.find(auth_grant.id)
47
+
48
+ refute auth_grant.permissions.has_key?(permissions.keys.first)
49
+ end
50
+
51
+
52
+ test "AUTHORIZE: user gets redirected to new form if not already authed" do
53
+ params = { :client_id => @client_app.client_id ,
54
+ :client_secret => @client_app.client_secret,
55
+ :redirect_uri => @redirect_uri }
56
+
57
+ as_user(@user).post oauth_authorize_path(params)
58
+
59
+ assert_equal 302, status
60
+ follow_redirect!
61
+ assert_equal oauth_new_path, path
62
+ end
63
+
64
+ end
@@ -0,0 +1,34 @@
1
+ ## NOT CAPYBARA
2
+ # ActionDispatch::IntegrationTest
3
+ # http://guides.rubyonrails.org/testing.html#integration-testing
4
+ # used so we can test POST actions ^_^
5
+
6
+ require 'test_helper'
7
+
8
+ class OauthTokenTest < ActionDispatch::IntegrationTest
9
+ setup do
10
+ @user = create_user
11
+ end
12
+
13
+
14
+ test "exchange a code for a token" do
15
+ user = create_user
16
+ auth_grant = create_auth_grant_for_user(user)
17
+ client = auth_grant.application
18
+ params = {:code => auth_grant.code,
19
+ :client_id => client.client_id,
20
+ :client_secret => client.client_secret}
21
+
22
+
23
+ as_user(@user).post oauth_token_path(params)
24
+
25
+ json_hash = JSON.parse(response.body)
26
+ assert json_hash["access_token"]
27
+ assert json_hash["access_token"], auth_grant.access_token
28
+
29
+ assert json_hash["refresh_token"]
30
+ assert json_hash["refresh_token"], auth_grant.refresh_token
31
+ end
32
+
33
+ end
34
+
@@ -0,0 +1,54 @@
1
+ ## NOT CAPYBARA
2
+ # ActionDispatch::IntegrationTest
3
+ # http://guides.rubyonrails.org/testing.html#integration-testing
4
+ # used so we can test POST actions ^_^
5
+
6
+ require 'test_helper'
7
+
8
+ class RefreshTokenTest < ActionDispatch::IntegrationTest
9
+ setup do
10
+ Timecop.freeze(Time.now)
11
+ Opro.setup do |config|
12
+ config.require_refresh_within = 1.month
13
+ end
14
+
15
+ @user = create_user
16
+ @auth_grant = create_auth_grant_for_user(@user)
17
+ @client_app = @auth_grant.application
18
+ end
19
+
20
+ teardown do
21
+ Timecop.return # "turn off" Timecop
22
+ end
23
+
24
+ test "clients get a valid refresh token" do
25
+ params = {:client_id => @client_app.client_id ,
26
+ :client_secret => @client_app.client_secret,
27
+ :code => @auth_grant.code}
28
+ as_user(@user).post oauth_token_path(params)
29
+ json_hash = JSON.parse(response.body)
30
+ assert_equal json_hash['expires_in'], @auth_grant.expires_in
31
+ end
32
+
33
+ test "exchange a refresh_token for an access_token" do
34
+ params = {:client_id => @client_app.client_id ,
35
+ :client_secret => @client_app.client_secret,
36
+ :refresh_token => @auth_grant.refresh_token}
37
+
38
+ Timecop.travel(2.days.from_now)
39
+
40
+ as_user(@user).post oauth_token_path(params)
41
+
42
+ json_hash = JSON.parse(response.body)
43
+ refute_equal json_hash['access_token'], @auth_grant.access_token
44
+ refute_equal json_hash['refresh_token'], @auth_grant.refresh_token
45
+ refute_equal json_hash['expires_in'], @auth_grant.expires_in
46
+
47
+
48
+ auth_grant = Oauth::AuthGrant.find(@auth_grant.id)
49
+ assert_equal json_hash['access_token'], auth_grant.access_token
50
+ assert_equal json_hash['refresh_token'], auth_grant.refresh_token
51
+ assert_equal json_hash['expires_in'], auth_grant.expires_in
52
+ end
53
+
54
+ end
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class AuthControllerTest < ActiveSupport::IntegrationCase
3
+ class CapybaraAuthControllerTest < ActiveSupport::IntegrationCase
4
4
 
5
5
  setup do
6
6
  @app = create_client_app
@@ -14,13 +14,14 @@ class AuthControllerTest < ActiveSupport::IntegrationCase
14
14
  end
15
15
 
16
16
  test 'auth entry point is accessible to logged IN users' do
17
+ as_user(@user) do
18
+ visit oauth_new_path(:client_id => @app.client_id, :redirect_uri => @redirect_uri)
17
19
 
18
- as_user(@user).visit oauth_new_path(:client_id => @app.client_id, :redirect_uri => @redirect_uri)
19
-
20
- assert_equal '/oauth/new', current_path
20
+ assert_equal '/oauth/new', current_path
21
+ click_button 'oauthAuthorize'
22
+ end
21
23
 
22
- click_button 'oauthAuthorize'
23
- access_grant = Oauth::AccessGrant.where(:user_id => @user.id, :application_id => @app.id).first
24
+ access_grant = Oauth::AuthGrant.where(:user_id => @user.id, :application_id => @app.id).first
24
25
  assert_equal @redirect_uri, current_path
25
26
  assert access_grant.present?
26
27
  assert access_grant.can?(:write) # write access is checked by default
@@ -31,7 +32,7 @@ class AuthControllerTest < ActiveSupport::IntegrationCase
31
32
 
32
33
  uncheck('permissions_write') # uncheck write access
33
34
  click_button 'oauthAuthorize'
34
- access_grant = Oauth::AccessGrant.where(:user_id => @user.id, :application_id => @app.id).first
35
+ access_grant = Oauth::AuthGrant.where(:user_id => @user.id, :application_id => @app.id).first
35
36
  refute access_grant.can?(:write)
36
37
  end
37
38
  end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class ClientAppControllerTest < ActiveSupport::IntegrationCase
4
+ test 'must be logged in' do
5
+ visit new_oauth_client_app_path
6
+ assert_equal '/users/sign_in', current_path
7
+ end
8
+
9
+ test 'create client application' do
10
+ user = create_user
11
+ as_user(user).visit new_oauth_client_app_path
12
+ assert_equal '/oauth_client_apps/new', current_path
13
+
14
+ fill_in 'oauth_client_app_name', :with => rand_name
15
+
16
+ click_button 'submitApp'
17
+ assert_equal '/oauth_client_apps', current_path
18
+
19
+ last_client = Oauth::ClientApp.order(:created_at).last
20
+ assert has_content?(last_client.name)
21
+ assert has_content?(last_client.client_id)
22
+ assert has_content?(last_client.client_secret)
23
+ end
24
+ end