opro 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG.md +3 -0
  2. data/Gemfile +39 -0
  3. data/Gemfile.lock +138 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +90 -0
  6. data/Rakefile +50 -0
  7. data/VERSION +1 -0
  8. data/app/controllers/oauth/auth_controller.rb +74 -0
  9. data/app/controllers/oauth/client_application_controller.rb +15 -0
  10. data/app/controllers/oauth/docs_controller.rb +36 -0
  11. data/app/controllers/opro_application_controller.rb +8 -0
  12. data/app/models/oauth/access_grant.rb +42 -0
  13. data/app/models/oauth/client_application.rb +30 -0
  14. data/app/views/oauth/auth/new.html.erb +8 -0
  15. data/app/views/oauth/client_application/create.html.erb +11 -0
  16. data/app/views/oauth/client_application/index.html.erb +18 -0
  17. data/app/views/oauth/client_application/new.html.erb +13 -0
  18. data/app/views/oauth/docs/index.html.erb +14 -0
  19. data/app/views/oauth/docs/markdown/curl.md.erb +6 -0
  20. data/app/views/oauth/docs/markdown/oauth.md.erb +1 -0
  21. data/app/views/oauth/docs/markdown/quick_start.md.erb +70 -0
  22. data/app/views/oauth/docs/show.html.erb +1 -0
  23. data/config/routes.rb +9 -0
  24. data/lib/generators/active_record/opro_generator.rb +28 -0
  25. data/lib/generators/active_record/templates/access_grants.rb +14 -0
  26. data/lib/generators/active_record/templates/client_applications.rb +11 -0
  27. data/lib/generators/opro/install_generator.rb +21 -0
  28. data/lib/generators/templates/opro.rb +4 -0
  29. data/lib/opro.rb +86 -0
  30. data/lib/opro/controllers/application_controller_helper.rb +38 -0
  31. data/lib/opro/engine.rb +8 -0
  32. data/opro.gemspec +148 -0
  33. data/test/dummy/Rakefile +7 -0
  34. data/test/dummy/app/controllers/application_controller.rb +3 -0
  35. data/test/dummy/app/controllers/pages_controller.rb +8 -0
  36. data/test/dummy/app/helpers/application_helper.rb +2 -0
  37. data/test/dummy/app/models/user.rb +10 -0
  38. data/test/dummy/app/views/layouts/application.html.erb +20 -0
  39. data/test/dummy/app/views/pages/index.html.erb +1 -0
  40. data/test/dummy/config.ru +4 -0
  41. data/test/dummy/config/application.rb +49 -0
  42. data/test/dummy/config/boot.rb +10 -0
  43. data/test/dummy/config/database.yml +22 -0
  44. data/test/dummy/config/environment.rb +5 -0
  45. data/test/dummy/config/environments/development.rb +26 -0
  46. data/test/dummy/config/environments/production.rb +49 -0
  47. data/test/dummy/config/environments/test.rb +35 -0
  48. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  49. data/test/dummy/config/initializers/devise.rb +223 -0
  50. data/test/dummy/config/initializers/inflections.rb +10 -0
  51. data/test/dummy/config/initializers/mime_types.rb +5 -0
  52. data/test/dummy/config/initializers/opro.rb +4 -0
  53. data/test/dummy/config/initializers/secret_token.rb +7 -0
  54. data/test/dummy/config/initializers/session_store.rb +8 -0
  55. data/test/dummy/config/locales/devise.en.yml +57 -0
  56. data/test/dummy/config/locales/en.yml +5 -0
  57. data/test/dummy/config/routes.rb +63 -0
  58. data/test/dummy/db/migrate/20120408163038_devise_create_users.rb +49 -0
  59. data/test/dummy/db/migrate/20120408165729_create_opro_access_grants.rb +14 -0
  60. data/test/dummy/db/migrate/20120408165730_create_opro_client_applications.rb +11 -0
  61. data/test/dummy/db/schema.rb +54 -0
  62. data/test/dummy/public/404.html +26 -0
  63. data/test/dummy/public/422.html +26 -0
  64. data/test/dummy/public/500.html +26 -0
  65. data/test/dummy/public/favicon.ico +0 -0
  66. data/test/dummy/public/javascripts/application.js +2 -0
  67. data/test/dummy/public/javascripts/controls.js +965 -0
  68. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  69. data/test/dummy/public/javascripts/effects.js +1123 -0
  70. data/test/dummy/public/javascripts/prototype.js +6001 -0
  71. data/test/dummy/public/javascripts/rails.js +202 -0
  72. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  73. data/test/dummy/script/rails +6 -0
  74. data/test/integration/auth_controller_test.rb +23 -0
  75. data/test/integration/client_application_controller_test.rb +24 -0
  76. data/test/integration/docs_controller_test.rb +8 -0
  77. data/test/integration/oauth_test.rb +17 -0
  78. data/test/opro_test.rb +24 -0
  79. data/test/support/integration_case.rb +5 -0
  80. data/test/test_helper.rb +99 -0
  81. metadata +251 -0
@@ -0,0 +1,3 @@
1
+ ## 0.0.1
2
+
3
+ Initial Release
data/Gemfile ADDED
@@ -0,0 +1,39 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "activesupport" , ">= 3.0.7"
4
+ gem "rails" , ">= 3.0.7"
5
+
6
+
7
+ gem 'bluecloth'
8
+
9
+ group :development, :test do
10
+ gem 'jeweler', "~> 1.6.4"
11
+ gem "bundler", ">= 1.1.3"
12
+
13
+
14
+ gem "capybara", ">= 0.4.0"
15
+ gem "sqlite3"
16
+ gem "launchy"
17
+ end
18
+
19
+
20
+ group :test, :development do
21
+ gem 'devise'
22
+ end
23
+
24
+
25
+ platforms :mri_18 do
26
+ group :development, :test do
27
+ gem "rcov"
28
+ end
29
+ end
30
+
31
+ platforms :mri_19 do
32
+ group :development, :test do
33
+ gem "simplecov"
34
+ end
35
+ end
36
+
37
+ # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
38
+ # gem 'ruby-debug'
39
+ # gem 'ruby-debug19'
@@ -0,0 +1,138 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ actionmailer (3.2.3)
5
+ actionpack (= 3.2.3)
6
+ mail (~> 2.4.4)
7
+ actionpack (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ journey (~> 1.0.1)
13
+ rack (~> 1.4.0)
14
+ rack-cache (~> 1.2)
15
+ rack-test (~> 0.6.1)
16
+ sprockets (~> 2.1.2)
17
+ activemodel (3.2.3)
18
+ activesupport (= 3.2.3)
19
+ builder (~> 3.0.0)
20
+ activerecord (3.2.3)
21
+ activemodel (= 3.2.3)
22
+ activesupport (= 3.2.3)
23
+ arel (~> 3.0.2)
24
+ tzinfo (~> 0.3.29)
25
+ activeresource (3.2.3)
26
+ activemodel (= 3.2.3)
27
+ activesupport (= 3.2.3)
28
+ activesupport (3.2.3)
29
+ i18n (~> 0.6)
30
+ multi_json (~> 1.0)
31
+ addressable (2.2.7)
32
+ arel (3.0.2)
33
+ bcrypt-ruby (3.0.1)
34
+ bluecloth (2.2.0)
35
+ builder (3.0.0)
36
+ capybara (1.1.2)
37
+ mime-types (>= 1.16)
38
+ nokogiri (>= 1.3.3)
39
+ rack (>= 1.0.0)
40
+ rack-test (>= 0.5.4)
41
+ selenium-webdriver (~> 2.0)
42
+ xpath (~> 0.1.4)
43
+ childprocess (0.3.1)
44
+ ffi (~> 1.0.6)
45
+ devise (2.0.4)
46
+ bcrypt-ruby (~> 3.0)
47
+ orm_adapter (~> 0.0.3)
48
+ railties (~> 3.1)
49
+ warden (~> 1.1.1)
50
+ erubis (2.7.0)
51
+ ffi (1.0.11)
52
+ git (1.2.5)
53
+ hike (1.2.1)
54
+ i18n (0.6.0)
55
+ jeweler (1.6.4)
56
+ bundler (~> 1.0)
57
+ git (>= 1.2.5)
58
+ rake
59
+ journey (1.0.3)
60
+ json (1.6.6)
61
+ launchy (2.1.0)
62
+ addressable (~> 2.2.6)
63
+ mail (2.4.4)
64
+ i18n (>= 0.4.0)
65
+ mime-types (~> 1.16)
66
+ treetop (~> 1.4.8)
67
+ mime-types (1.18)
68
+ multi_json (1.2.0)
69
+ nokogiri (1.5.2)
70
+ orm_adapter (0.0.7)
71
+ polyglot (0.3.3)
72
+ rack (1.4.1)
73
+ rack-cache (1.2)
74
+ rack (>= 0.4)
75
+ rack-ssl (1.3.2)
76
+ rack
77
+ rack-test (0.6.1)
78
+ rack (>= 1.0)
79
+ rails (3.2.3)
80
+ actionmailer (= 3.2.3)
81
+ actionpack (= 3.2.3)
82
+ activerecord (= 3.2.3)
83
+ activeresource (= 3.2.3)
84
+ activesupport (= 3.2.3)
85
+ bundler (~> 1.0)
86
+ railties (= 3.2.3)
87
+ railties (3.2.3)
88
+ actionpack (= 3.2.3)
89
+ activesupport (= 3.2.3)
90
+ rack-ssl (~> 1.3.2)
91
+ rake (>= 0.8.7)
92
+ rdoc (~> 3.4)
93
+ thor (~> 0.14.6)
94
+ rake (0.9.2.2)
95
+ rcov (1.0.0)
96
+ rdoc (3.12)
97
+ json (~> 1.4)
98
+ rubyzip (0.9.7)
99
+ selenium-webdriver (2.20.0)
100
+ childprocess (>= 0.2.5)
101
+ ffi (~> 1.0)
102
+ multi_json (~> 1.0)
103
+ rubyzip
104
+ simplecov (0.6.1)
105
+ multi_json (~> 1.0)
106
+ simplecov-html (~> 0.5.3)
107
+ simplecov-html (0.5.3)
108
+ sprockets (2.1.2)
109
+ hike (~> 1.2)
110
+ rack (~> 1.0)
111
+ tilt (~> 1.1, != 1.3.0)
112
+ sqlite3 (1.3.5)
113
+ thor (0.14.6)
114
+ tilt (1.3.3)
115
+ treetop (1.4.10)
116
+ polyglot
117
+ polyglot (>= 0.3.1)
118
+ tzinfo (0.3.33)
119
+ warden (1.1.1)
120
+ rack (>= 1.0)
121
+ xpath (0.1.4)
122
+ nokogiri (~> 1.3)
123
+
124
+ PLATFORMS
125
+ ruby
126
+
127
+ DEPENDENCIES
128
+ activesupport (>= 3.0.7)
129
+ bluecloth
130
+ bundler (>= 1.1.3)
131
+ capybara (>= 0.4.0)
132
+ devise
133
+ jeweler (~> 1.6.4)
134
+ launchy
135
+ rails (>= 3.0.7)
136
+ rcov
137
+ simplecov
138
+ sqlite3
@@ -0,0 +1,20 @@
1
+ Copyright 2011 Schneems
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,90 @@
1
+ ## Stop, Read This
2
+
3
+ This is my first time writing and Oauth Provider, so there may be buggy or insecure code. If you want to use this, do so at your own risk. I'm vetting it on some development and production applications, when it is ready for consumption and contribution, i'll remove this. If you want to be notified when that happens let me know [@schneems](http://twitter.com/schneems). For now this should be considered a toy, and enjoyed as such :)
4
+
5
+ ## Opro
6
+
7
+ A Rails Engine that turns your app into an [Oauth](http://oauth.net/2/) Provider.
8
+
9
+
10
+ ## What is an Oauth Provider
11
+
12
+ Oauth is used all over the web by apps that need to authenticate users or restrict access to information in a secure fashion. Twitter and Facebook are the best known Oauth Providers. Users click "connect to Twitter" in an iPhone app, then they're sent over to Twitter's site where they can accept or deny access. From there they're sent back to the iPhone app where they can do anything through the API that they would be allowed to do in the website.
13
+
14
+ Most users understand the flow pretty well, it's a fairly standard process, and is secure. While there are plenty of Oauth client libraries unfortunately it's not super easy to implement from a provider standpoint. Since I hate writing code twice, I decided to take an Oauth Provider and turn it into a Rails Engine so anyone could implement an Oauth Provider on their site.
15
+
16
+ ## Why would I use this?
17
+
18
+ Lets say you've built a Rails app, awesome. Now you want to build a mobile app on say, the iPhone; cool. You start throwing around `#to_json` like nobody's business, but then you realize you need to authenticate users somehow. "Basic Auth!!", you exclaim, but then you realize that's not the most secure solution. You also realize that some users already signed up with Facebook & Twitter so they don't have a username/password combo. What ever shall you do?
19
+
20
+ Wouldn't it be great if we could have a token exchange where the user goes to a mobile web view and grants permission, and then we return back an auth token just like the big boys (Facebook, Twitter, *cough* Foursquare *cough*). With Opro, we can add this functionality pretty easily. We'll use your existing authentication strategy and provide some end integration points for your clients to use out of the box.
21
+
22
+ ## Sounds Hard
23
+
24
+ It's not, just follow the directions below. I'll add a screencast and example app when I get time. Any questions, open an issue or ping me on Twitter.
25
+
26
+ ## Install
27
+
28
+ Gemfile
29
+
30
+ ```ruby
31
+ gem 'opro'
32
+ ```
33
+
34
+ ```shell
35
+ $ bundle install
36
+ ```
37
+
38
+ ```shell
39
+ $ opro:install
40
+ ```
41
+
42
+ This will put a file in `initializers/opro.rb` and generate some migrations.
43
+
44
+ Go to `initializers/opro.rb` and configure your app for your authentication scheme.
45
+
46
+ ```ruby
47
+ Opro.setup do |config|
48
+ config.auth_strategy = :devise
49
+ end
50
+ ```
51
+
52
+ If you're not using devise you can manually configure your own auth strategy. In the future I plan on adding more auth strategies, ping me or submit a pull request for your desired authentication scheme.
53
+
54
+ ```ruby
55
+ Opro.setup do |config|
56
+ config.login_method { |controller, current_user| controller.sign_in(current_user, :bypass => true) }
57
+ config.logout_method { |controller, current_user| controller.sign_out(current_user) }
58
+ config.authenticate_user_method { |controller| controller.authenticate_user! }
59
+ end
60
+ ```
61
+
62
+ Now we're ready to migrate the database
63
+
64
+ ```shell
65
+ $ rake db:migrate
66
+ ````
67
+
68
+
69
+
70
+ That should be all you need to do to get setup, congrats you're now able to authenticate users using OAuth!!
71
+
72
+
73
+ ## Use it
74
+
75
+ Opro comes with built in documentation, so if you start your server you can view them at `/docs/oauth`. If you're reading this on Github you can jump right to the [Quick Start](/app/views/docs/markdown/quick_start.md) guide. This guide will walk you through creating your first Oauth client application, giving access to that app as a logged in user, getting an access token for that user, and using that token to access the server as an authenticated user!
76
+
77
+
78
+ ## Assumptions
79
+
80
+ * You have a user model and that is what your authenticating
81
+ * You're using Active::Record
82
+
83
+ If you submit a _good_ pull request for other adapters, or for generalizing the resource we're authenticating, you'll make me pretty happy.
84
+
85
+
86
+ ## About
87
+
88
+ If you have a question file an issue or, find me on the Twitters [@schneems](http://twitter.com/schneems).
89
+
90
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,50 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+
5
+ begin
6
+ Bundler.setup(:default, :development, :test)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+
13
+ require 'rake'
14
+ require 'rdoc/task'
15
+
16
+ require 'rake/testtask'
17
+
18
+ Rake::TestTask.new(:test) do |t|
19
+ t.libs << 'lib'
20
+ t.libs << 'test'
21
+ t.pattern = 'test/**/*_test.rb'
22
+ t.verbose = false
23
+ end
24
+
25
+ task :default => :test
26
+
27
+ Rake::RDocTask.new(:rdoc) do |rdoc|
28
+ rdoc.rdoc_dir = 'rdoc'
29
+ rdoc.title = 'Opro'
30
+ rdoc.options << '--line-numbers' << '--inline-source'
31
+ rdoc.rdoc_files.include('README.rdoc')
32
+ rdoc.rdoc_files.include('lib/**/*.rb')
33
+ end
34
+
35
+
36
+ require 'jeweler'
37
+ Jeweler::Tasks.new do |gem|
38
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
39
+ gem.name = "opro"
40
+ gem.homepage = "http://github.com/schneems/opro"
41
+ gem.license = "MIT"
42
+ gem.summary = %Q{ Opro turns your Rails application into an OAuth Provider }
43
+ gem.description = %Q{ Enable oauth clients (iphone, android, web sites, etc.) to access and use your Rails application, what you do with it is up to you}
44
+ gem.email = "richard.schneeman@gmail.com"
45
+ gem.authors = ["schneems"]
46
+ # dependencies defined in Gemfile
47
+ end
48
+ Jeweler::RubygemsDotOrgTasks.new
49
+
50
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1.pre
@@ -0,0 +1,74 @@
1
+ class Oauth::AuthController < ApplicationController
2
+ before_filter :opro_authenticate_user!, :except => [:access_token]
3
+ skip_before_filter :verify_authenticity_token, :only => [:access_token, :user]
4
+ before_filter :ask_user!, :only => :authorize
5
+
6
+ def new
7
+ @redirect_uri = params[:redirect_uri]
8
+ @client_app = Oauth::ClientApplication.find_by_app_id(params[:client_id])
9
+ end
10
+
11
+ def authorize
12
+ application = Oauth::ClientApplication.find_by_app_id(params[:client_id])
13
+ access_grant = Oauth::AccessGrant.where( :user_id => current_user.id, :application_id => application.id).first
14
+ access_grant ||= Oauth::AccessGrant.create(:user => current_user, :application => application)
15
+ redirect_to access_grant.redirect_uri_for(params[:redirect_uri])
16
+ end
17
+
18
+ def access_token
19
+ application = Oauth::ClientApplication.authenticate(params[:client_id], params[:client_secret])
20
+
21
+ if application.nil?
22
+ render :json => {:error => "Could not find application"}
23
+ return
24
+ end
25
+
26
+ access_grant = Oauth::AccessGrant.authenticate(params[:code], application.id)
27
+
28
+ if access_grant.nil?
29
+ render :json => {:error => "Could not authenticate access code"}
30
+ return
31
+ end
32
+
33
+ access_grant.start_expiry_period!
34
+ render :json => {:access_token => access_grant.access_token, :refresh_token => access_grant.refresh_token, :expires_in => access_grant.access_token_expires_at}
35
+ end
36
+
37
+ # When a user is sent to authorize an application they must first accept the authorization
38
+ # if they've already authed the app, they skip this section
39
+ def ask_user!
40
+ if user_granted_access_before?(current_user, params)
41
+ # Re-Authorize the application, do not ask the user
42
+ return true
43
+ elsif user_authorizes_the_request?(request)
44
+ # Authorize the application, do not ask the user
45
+ return true
46
+ else
47
+ # if the request did not come from a form within the application, render the user form
48
+ @redirect_uri ||= params[:redirect_uri]
49
+ @client_app ||= Oauth::ClientApplication.find_by_app_id(params[:client_id])
50
+ redirect_to oauth_new_path(params)
51
+ end
52
+ end
53
+
54
+ private
55
+ def user_granted_access_before?(user, params)
56
+ @client_app ||= Oauth::ClientApplication.find_by_app_id(params[:client_id])
57
+ Oauth::AccessGrant.where(:application_id => @client_app.id, :user_id => user.id).present?
58
+ end
59
+
60
+
61
+ # We're verifying that a post was made from our own site, indicating a user confirmed via form
62
+ def user_authorizes_the_request?(request)
63
+ request.post? && referrer_is_self?(request)
64
+ end
65
+
66
+ # Ensures that the referrer is also the current host, to prevent spoofing
67
+ def referrer_is_self?(request)
68
+ return false if request.referrer.blank?
69
+ referrer_host = URI.parse(request.referrer).host
70
+ self_host = URI.parse(request.url).host
71
+ referrer_host == self_host
72
+ end
73
+
74
+ end
@@ -0,0 +1,15 @@
1
+ class Oauth::ClientApplicationController < ApplicationController
2
+ before_filter :opro_authenticate_user!
3
+
4
+ def new
5
+ @client_app = Oauth::ClientApplication.new
6
+ end
7
+
8
+ def create
9
+ @client_app = Oauth::ClientApplication.create_with_user_and_name(current_user, params[:oauth_client_application][:name])
10
+ end
11
+
12
+ def index
13
+ @client_apps = Oauth::ClientApplication.where(:user_id => current_user.id)
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ require 'erb'
2
+ OPRO_MD_ROOT=File.join(File.dirname(__FILE__), '../../views/oauth/docs/markdown/')
3
+
4
+
5
+ class Oauth::DocsController < ApplicationController
6
+ helper_method :render_doc
7
+
8
+ def index
9
+ end
10
+
11
+ def show
12
+ @doc = params[:id]
13
+ end
14
+
15
+ def render_doc(name)
16
+ str = read_file(name.to_s)
17
+ str = parse_erb(str)
18
+ str = parse_markdown(str)
19
+ str.html_safe
20
+ end
21
+
22
+ private
23
+
24
+ def parse_erb(str)
25
+ ERB.new(str).result(binding)
26
+ end
27
+
28
+ def parse_markdown(str)
29
+ BlueCloth.new(str).to_html
30
+ end
31
+
32
+ def read_file(name)
33
+ name = OPRO_MD_ROOT + name
34
+ File.open(name + '.md.erb' ).read.to_s
35
+ end
36
+ end