google_authentication 0.1.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.
Files changed (78) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +28 -0
  5. data/Guardfile +20 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.markdown +150 -0
  8. data/Rakefile +45 -0
  9. data/VERSION +1 -0
  10. data/app/controllers/google_authentication/omniauth_callbacks_controller.rb +11 -0
  11. data/app/controllers/google_authentication/sessions_controller.rb +10 -0
  12. data/config/routes.rb +11 -0
  13. data/features/google_authentication.feature +27 -0
  14. data/features/step_definitions/google_authentication_steps.rb +19 -0
  15. data/features/support/env.rb +24 -0
  16. data/google_authentication.gemspec +155 -0
  17. data/lib/generators/google_authentication/google_authentication_generator.rb +46 -0
  18. data/lib/generators/google_authentication/install_generator.rb +27 -0
  19. data/lib/generators/templates/MODEL.warning +10 -0
  20. data/lib/generators/templates/README +11 -0
  21. data/lib/generators/templates/google_authentication.rb +14 -0
  22. data/lib/generators/templates/migration.rb +27 -0
  23. data/lib/google_authentication.rb +43 -0
  24. data/lib/google_authentication/acts_as_google_user.rb +77 -0
  25. data/lib/google_authentication/engine.rb +19 -0
  26. data/spec/dummy/Rakefile +7 -0
  27. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  28. data/spec/dummy/app/controllers/posts_controller.rb +83 -0
  29. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec/dummy/app/helpers/posts_helper.rb +2 -0
  31. data/spec/dummy/app/models/post.rb +2 -0
  32. data/spec/dummy/app/models/user.rb +5 -0
  33. data/spec/dummy/app/views/layouts/application.html.erb +23 -0
  34. data/spec/dummy/app/views/posts/_form.html.erb +25 -0
  35. data/spec/dummy/app/views/posts/edit.html.erb +6 -0
  36. data/spec/dummy/app/views/posts/index.html.erb +25 -0
  37. data/spec/dummy/app/views/posts/new.html.erb +5 -0
  38. data/spec/dummy/app/views/posts/show.html.erb +15 -0
  39. data/spec/dummy/config.ru +4 -0
  40. data/spec/dummy/config/application.rb +45 -0
  41. data/spec/dummy/config/boot.rb +10 -0
  42. data/spec/dummy/config/database.yml +22 -0
  43. data/spec/dummy/config/environment.rb +5 -0
  44. data/spec/dummy/config/environments/development.rb +26 -0
  45. data/spec/dummy/config/environments/production.rb +49 -0
  46. data/spec/dummy/config/environments/test.rb +35 -0
  47. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  48. data/spec/dummy/config/initializers/devise.rb +204 -0
  49. data/spec/dummy/config/initializers/inflections.rb +10 -0
  50. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  51. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  52. data/spec/dummy/config/initializers/session_store.rb +8 -0
  53. data/spec/dummy/config/locales/devise.en.yml +53 -0
  54. data/spec/dummy/config/locales/en.yml +5 -0
  55. data/spec/dummy/config/routes.rb +6 -0
  56. data/spec/dummy/db/migrate/20110630105039_create_posts.rb +14 -0
  57. data/spec/dummy/db/migrate/20110630111038_devise_create_users.rb +18 -0
  58. data/spec/dummy/db/schema.rb +34 -0
  59. data/spec/dummy/public/404.html +26 -0
  60. data/spec/dummy/public/422.html +26 -0
  61. data/spec/dummy/public/500.html +26 -0
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/dummy/public/javascripts/application.js +2 -0
  64. data/spec/dummy/public/javascripts/controls.js +965 -0
  65. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  66. data/spec/dummy/public/javascripts/effects.js +1123 -0
  67. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  68. data/spec/dummy/public/javascripts/rails.js +191 -0
  69. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  70. data/spec/dummy/public/stylesheets/scaffold.css +56 -0
  71. data/spec/dummy/script/rails +6 -0
  72. data/spec/generators/google_authentication_generator_spec.rb +39 -0
  73. data/spec/generators/install_generator_spec.rb +23 -0
  74. data/spec/google_authentication_spec.rb +28 -0
  75. data/spec/integration/navigation_spec.rb +22 -0
  76. data/spec/models/acts_as_google_user_spec.rb +67 -0
  77. data/spec/spec_helper.rb +37 -0
  78. metadata +289 -0
@@ -0,0 +1,191 @@
1
+ (function() {
2
+ // Technique from Juriy Zaytsev
3
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4
+ function isEventSupported(eventName) {
5
+ var el = document.createElement('div');
6
+ eventName = 'on' + eventName;
7
+ var isSupported = (eventName in el);
8
+ if (!isSupported) {
9
+ el.setAttribute(eventName, 'return;');
10
+ isSupported = typeof el[eventName] == 'function';
11
+ }
12
+ el = null;
13
+ return isSupported;
14
+ }
15
+
16
+ function isForm(element) {
17
+ return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18
+ }
19
+
20
+ function isInput(element) {
21
+ if (Object.isElement(element)) {
22
+ var name = element.nodeName.toUpperCase()
23
+ return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24
+ }
25
+ else return false
26
+ }
27
+
28
+ var submitBubbles = isEventSupported('submit'),
29
+ changeBubbles = isEventSupported('change')
30
+
31
+ if (!submitBubbles || !changeBubbles) {
32
+ // augment the Event.Handler class to observe custom events when needed
33
+ Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34
+ function(init, element, eventName, selector, callback) {
35
+ init(element, eventName, selector, callback)
36
+ // is the handler being attached to an element that doesn't support this event?
37
+ if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38
+ (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39
+ // "submit" => "emulated:submit"
40
+ this.eventName = 'emulated:' + this.eventName
41
+ }
42
+ }
43
+ )
44
+ }
45
+
46
+ if (!submitBubbles) {
47
+ // discover forms on the page by observing focus events which always bubble
48
+ document.on('focusin', 'form', function(focusEvent, form) {
49
+ // special handler for the real "submit" event (one-time operation)
50
+ if (!form.retrieve('emulated:submit')) {
51
+ form.on('submit', function(submitEvent) {
52
+ var emulated = form.fire('emulated:submit', submitEvent, true)
53
+ // if custom event received preventDefault, cancel the real one too
54
+ if (emulated.returnValue === false) submitEvent.preventDefault()
55
+ })
56
+ form.store('emulated:submit', true)
57
+ }
58
+ })
59
+ }
60
+
61
+ if (!changeBubbles) {
62
+ // discover form inputs on the page
63
+ document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64
+ // special handler for real "change" events
65
+ if (!input.retrieve('emulated:change')) {
66
+ input.on('change', function(changeEvent) {
67
+ input.fire('emulated:change', changeEvent, true)
68
+ })
69
+ input.store('emulated:change', true)
70
+ }
71
+ })
72
+ }
73
+
74
+ function handleRemote(element) {
75
+ var method, url, params;
76
+
77
+ var event = element.fire("ajax:before");
78
+ if (event.stopped) return false;
79
+
80
+ if (element.tagName.toLowerCase() === 'form') {
81
+ method = element.readAttribute('method') || 'post';
82
+ url = element.readAttribute('action');
83
+ params = element.serialize();
84
+ } else {
85
+ method = element.readAttribute('data-method') || 'get';
86
+ url = element.readAttribute('href');
87
+ params = {};
88
+ }
89
+
90
+ new Ajax.Request(url, {
91
+ method: method,
92
+ parameters: params,
93
+ evalScripts: true,
94
+
95
+ onComplete: function(request) { element.fire("ajax:complete", request); },
96
+ onSuccess: function(request) { element.fire("ajax:success", request); },
97
+ onFailure: function(request) { element.fire("ajax:failure", request); }
98
+ });
99
+
100
+ element.fire("ajax:after");
101
+ }
102
+
103
+ function handleMethod(element) {
104
+ var method = element.readAttribute('data-method'),
105
+ url = element.readAttribute('href'),
106
+ csrf_param = $$('meta[name=csrf-param]')[0],
107
+ csrf_token = $$('meta[name=csrf-token]')[0];
108
+
109
+ var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110
+ element.parentNode.insert(form);
111
+
112
+ if (method !== 'post') {
113
+ var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114
+ form.insert(field);
115
+ }
116
+
117
+ if (csrf_param) {
118
+ var param = csrf_param.readAttribute('content'),
119
+ token = csrf_token.readAttribute('content'),
120
+ field = new Element('input', { type: 'hidden', name: param, value: token });
121
+ form.insert(field);
122
+ }
123
+
124
+ form.submit();
125
+ }
126
+
127
+
128
+ document.on("click", "*[data-confirm]", function(event, element) {
129
+ var message = element.readAttribute('data-confirm');
130
+ if (!confirm(message)) event.stop();
131
+ });
132
+
133
+ document.on("click", "a[data-remote]", function(event, element) {
134
+ if (event.stopped) return;
135
+ handleRemote(element);
136
+ event.stop();
137
+ });
138
+
139
+ document.on("click", "a[data-method]", function(event, element) {
140
+ if (event.stopped) return;
141
+ handleMethod(element);
142
+ event.stop();
143
+ });
144
+
145
+ document.on("submit", function(event) {
146
+ var element = event.findElement(),
147
+ message = element.readAttribute('data-confirm');
148
+ if (message && !confirm(message)) {
149
+ event.stop();
150
+ return false;
151
+ }
152
+
153
+ var inputs = element.select("input[type=submit][data-disable-with]");
154
+ inputs.each(function(input) {
155
+ input.disabled = true;
156
+ input.writeAttribute('data-original-value', input.value);
157
+ input.value = input.readAttribute('data-disable-with');
158
+ });
159
+
160
+ var element = event.findElement("form[data-remote]");
161
+ if (element) {
162
+ handleRemote(element);
163
+ event.stop();
164
+ }
165
+ });
166
+
167
+ document.on("ajax:after", "form", function(event, element) {
168
+ var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169
+ inputs.each(function(input) {
170
+ input.value = input.readAttribute('data-original-value');
171
+ input.removeAttribute('data-original-value');
172
+ input.disabled = false;
173
+ });
174
+ });
175
+
176
+ Ajax.Responders.register({
177
+ onCreate: function(request) {
178
+ var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
179
+
180
+ if (csrf_meta_tag) {
181
+ var header = 'X-CSRF-Token',
182
+ token = csrf_meta_tag.readAttribute('content');
183
+
184
+ if (!request.options.requestHeaders) {
185
+ request.options.requestHeaders = {};
186
+ }
187
+ request.options.requestHeaders[header] = token;
188
+ }
189
+ }
190
+ });
191
+ })();
File without changes
@@ -0,0 +1,56 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ div.field, div.actions {
20
+ margin-bottom: 10px;
21
+ }
22
+
23
+ #notice {
24
+ color: green;
25
+ }
26
+
27
+ .field_with_errors {
28
+ padding: 2px;
29
+ background-color: red;
30
+ display: table;
31
+ }
32
+
33
+ #error_explanation {
34
+ width: 450px;
35
+ border: 2px solid red;
36
+ padding: 7px;
37
+ padding-bottom: 0;
38
+ margin-bottom: 20px;
39
+ background-color: #f0f0f0;
40
+ }
41
+
42
+ #error_explanation h2 {
43
+ text-align: left;
44
+ font-weight: bold;
45
+ padding: 5px 5px 5px 15px;
46
+ font-size: 12px;
47
+ margin: -7px;
48
+ margin-bottom: 0px;
49
+ background-color: #c00;
50
+ color: #fff;
51
+ }
52
+
53
+ #error_explanation ul li {
54
+ font-size: 12px;
55
+ list-style: square;
56
+ }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ require File.expand_path('../../../lib/generators/google_authentication/google_authentication_generator', __FILE__)
4
+
5
+ describe GoogleAuthentication::Generators::GoogleAuthenticationGenerator do
6
+ include GeneratorSpec::TestCase
7
+ destination File.expand_path("../../../tmp", __FILE__)
8
+
9
+ before(:each) do
10
+ prepare_destination
11
+ end
12
+
13
+ it "should create a migration and a model file" do
14
+ run_generator %w(monster)
15
+ assert_file "app/models/monster.rb", /acts_as_google_user/
16
+ assert_migration "db/migrate/devise_create_monsters.rb"
17
+ end
18
+
19
+ it "should delete all files when revoked" do
20
+ run_generator %w(monster)
21
+ run_generator %w(monster), :behavior => :revoke
22
+ assert_no_file "app/models/monster.rb"
23
+ assert_no_migration "db/migrate/devise_create_monsters.rb"
24
+ end
25
+
26
+ it "should show a readme when model is different from user" do
27
+ output = run_generator %w(monster)
28
+ output.should match /You should edit the google_authentication initializer/
29
+ output.should match /config\.model_name = :your-model-name/
30
+ end
31
+
32
+ it "should include google default fields when run with no fields" do
33
+ run_generator %w(account)
34
+ assert_field_type :email, :text_field
35
+ assert_field_type :first_name, :text_field
36
+ assert_field_type :last_name, :text_field
37
+ end
38
+ end
39
+
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ require File.expand_path('../../../lib/generators/google_authentication/install_generator', __FILE__)
4
+
5
+ describe GoogleAuthentication::Generators::InstallGenerator do
6
+ include GeneratorSpec::TestCase
7
+ destination File.expand_path("../../../tmp", __FILE__)
8
+
9
+ before(:each) do
10
+ prepare_destination
11
+ end
12
+
13
+ it "creates an initializer file" do
14
+ run_generator
15
+ assert_file "config/initializers/google_authentication.rb", /GoogleAuthentication.setup do |config|/
16
+ assert_file "config/initializers/devise.rb", /Devise.setup do |config|/
17
+ end
18
+
19
+ it "accept an option for domain and put it in the initializer file" do
20
+ run_generator %w(--domain domain.com)
21
+ assert_file "config/initializers/google_authentication.rb", /config\.domain = 'domain\.com'/
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoogleAuthentication do
4
+ it "should be valid" do
5
+ GoogleAuthentication.should be_a(Module)
6
+ end
7
+
8
+ describe "#define_routes?" do
9
+
10
+ it "should return true with existent class" do
11
+ # User model is defined in the dummy application
12
+ GoogleAuthentication.stub(:model_name).and_return(:user)
13
+ GoogleAuthentication.define_routes?.should be_true
14
+ end
15
+
16
+ it "should return false with non existent class" do
17
+ GoogleAuthentication.stub(:model_name).and_return(:monster)
18
+ GoogleAuthentication.define_routes?.should be_false
19
+ end
20
+ end
21
+
22
+ describe "#devise_table" do
23
+ it "should return a plural symbol" do
24
+ GoogleAuthentication.stub(:model_name).and_return(:monster)
25
+ GoogleAuthentication.devise_table.should eql(:monsters)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Navigation" do
4
+ include Capybara::DSL
5
+
6
+ it "should be a valid app" do
7
+ ::Rails.application.should be_a(Dummy::Application)
8
+ end
9
+
10
+ it 'should redirect to auth path when requesting sign_in' do
11
+ get '/sign_in'
12
+ response.should be_redirect
13
+ end
14
+
15
+ it 'should sign in and redirect with a flash message when calling callback' do
16
+ User.stub(:find_or_create_by_omniauth_impl).and_return(User.new)
17
+ get '/users/auth/google_apps/callback'
18
+ response.should be_redirect
19
+ flash[:notice].should match('Google')
20
+ end
21
+
22
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoogleAuthentication::ActsAsGoogleUser do
4
+
5
+ class DefaultUser < ActiveRecord::Base
6
+ set_table_name :users
7
+ acts_as_google_user
8
+ end
9
+
10
+ class RememberableUser < ActiveRecord::Base
11
+ set_table_name :users
12
+ acts_as_google_user :rememberable
13
+ end
14
+
15
+ class ForbiddenUser < ActiveRecord::Base
16
+ set_table_name :users
17
+ acts_as_google_user :database_authenticable, :recoverable
18
+ end
19
+
20
+ # all kind of users should include :omniauthable module
21
+ shared_examples_for "All Users" do
22
+ it "should have omniauthable module" do
23
+ subject.class.devise_modules.should include(:omniauthable)
24
+ end
25
+ end
26
+
27
+ describe DefaultUser do
28
+
29
+ subject { DefaultUser.new }
30
+
31
+ it_should_behave_like "All Users"
32
+
33
+ it "should respond to a class method finder" do
34
+ subject.class.respond_to?(:find_or_create_by_omniauth_uid).should be_true
35
+ end
36
+
37
+ it "should have only omniauthable module" do
38
+ subject.class.devise_modules.should eql [:omniauthable]
39
+ end
40
+ end
41
+
42
+ describe "Users with different devise modules" do
43
+
44
+ describe RememberableUser do
45
+
46
+ subject { RememberableUser.new }
47
+
48
+ it_should_behave_like "All Users"
49
+
50
+ it "should have rememberable module" do
51
+ subject.class.devise_modules.should include :rememberable
52
+ end
53
+ end
54
+
55
+ describe ForbiddenUser do
56
+ subject { ForbiddenUser.new }
57
+
58
+ it_should_behave_like "All Users"
59
+
60
+ it "should not include forbidden modules" do
61
+ subject.class.devise_modules.should eql [:omniauthable]
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,37 @@
1
+ # Configure Rails Envinronment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+ require "rspec/rails"
7
+ require "generator_spec/test_case"
8
+
9
+ ActionMailer::Base.delivery_method = :test
10
+ ActionMailer::Base.perform_deliveries = true
11
+ ActionMailer::Base.default_url_options[:host] = "test.com"
12
+
13
+ Rails.backtrace_cleaner.remove_silencers!
14
+
15
+ # Configure capybara for integration testing
16
+ require "capybara/rails"
17
+ Capybara.default_driver = :rack_test
18
+ Capybara.default_selector = :css
19
+
20
+ # Run any available migration
21
+ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
22
+
23
+ # Load support files
24
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
25
+
26
+ # Omniauth test mode
27
+ OmniAuth.config.test_mode = true
28
+
29
+ RSpec.configure do |config|
30
+ # Remove this line if you don't want RSpec's should and should_not
31
+ # methods or matchers
32
+ require 'rspec/expectations'
33
+ config.include RSpec::Matchers
34
+
35
+ # == Mock Framework
36
+ config.mock_with :rspec
37
+ end