openid_fu_generator 0.0.1

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 (49) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +48 -0
  4. data/README.txt +48 -0
  5. data/Rakefile +4 -0
  6. data/config/hoe.rb +72 -0
  7. data/config/requirements.rb +15 -0
  8. data/lib/openid_fu.rb +10 -0
  9. data/lib/openid_fu/association.rb +12 -0
  10. data/lib/openid_fu/controller_methods.rb +97 -0
  11. data/lib/openid_fu/nonce.rb +5 -0
  12. data/lib/openid_fu/openid_ar_store.rb +62 -0
  13. data/lib/openid_fu/openid_attribute_types.rb +79 -0
  14. data/lib/openid_fu/openid_ax_ext.rb +12 -0
  15. data/lib/openid_fu/openid_setting.rb +5 -0
  16. data/lib/openid_fu/version.rb +9 -0
  17. data/openid_fu_generator.rb +246 -0
  18. data/script/console +10 -0
  19. data/script/destroy +14 -0
  20. data/script/generate +14 -0
  21. data/script/txt2html +74 -0
  22. data/setup.rb +1585 -0
  23. data/tasks/deployment.rake +34 -0
  24. data/tasks/environment.rake +7 -0
  25. data/tasks/website.rake +17 -0
  26. data/templates/activation.html.erb +3 -0
  27. data/templates/authenticated_system.rb +155 -0
  28. data/templates/authenticated_test_helper.rb +94 -0
  29. data/templates/controller.rb +111 -0
  30. data/templates/fixtures.yml +15 -0
  31. data/templates/functional_test.rb +87 -0
  32. data/templates/helper.rb +2 -0
  33. data/templates/login.html.erb +20 -0
  34. data/templates/migration.rb +55 -0
  35. data/templates/model.rb +92 -0
  36. data/templates/model_controller.rb +30 -0
  37. data/templates/model_functional_test.rb +64 -0
  38. data/templates/model_helper.rb +2 -0
  39. data/templates/notifier.rb +25 -0
  40. data/templates/notifier_test.rb +31 -0
  41. data/templates/observer.rb +11 -0
  42. data/templates/open_id_form.html.erb +13 -0
  43. data/templates/restore_location.html.erb +30 -0
  44. data/templates/signup.html.erb +19 -0
  45. data/templates/signup_notification.html.erb +8 -0
  46. data/templates/unit_test.rb +94 -0
  47. data/test/test_helper.rb +4 -0
  48. data/test/test_openid_fu.rb +11 -0
  49. metadata +108 -0
@@ -0,0 +1,34 @@
1
+ desc 'Release the website and new gem version'
2
+ task :deploy => [:check_version, :website, :release] do
3
+ puts "Remember to create SVN tag:"
4
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
5
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6
+ puts "Suggested comment:"
7
+ puts "Tagging release #{CHANGES}"
8
+ end
9
+
10
+ desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11
+ task :local_deploy => [:website_generate, :install_gem]
12
+
13
+ task :check_version do
14
+ unless ENV['VERSION']
15
+ puts 'Must pass a VERSION=x.y.z release version'
16
+ exit
17
+ end
18
+ unless ENV['VERSION'] == VERS
19
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
20
+ exit
21
+ end
22
+ end
23
+
24
+ desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
25
+ task :install_gem_no_doc => [:clean, :package] do
26
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
27
+ end
28
+
29
+ namespace :manifest do
30
+ desc 'Recreate Manifest.txt to include ALL files'
31
+ task :refresh do
32
+ `rake check_manifest | patch -p0 > Manifest.txt`
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
@@ -0,0 +1,17 @@
1
+ desc 'Generate website files'
2
+ task :website_generate => :ruby_env do
3
+ (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4
+ sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5
+ end
6
+ end
7
+
8
+ desc 'Upload website files to rubyforge'
9
+ task :website_upload do
10
+ host = "#{rubyforge_username}@rubyforge.org"
11
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
12
+ local_dir = 'website'
13
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
14
+ end
15
+
16
+ desc 'Generate and upload website files'
17
+ task :website => [:website_generate, :website_upload, :publish_docs]
@@ -0,0 +1,3 @@
1
+ <%%= @<%= file_name %>.login %>, your account has been activated. You may now start adding your plugins:
2
+
3
+ <%%= @url %>
@@ -0,0 +1,155 @@
1
+ module AuthenticatedSystem
2
+ protected
3
+ # Returns true or false if the user is logged in.
4
+ # Preloads @current_<%= file_name %> with the user model if they're logged in.
5
+ def logged_in?
6
+ current_<%= file_name %> != :false
7
+ end
8
+
9
+ # Accesses the current <%= file_name %> from the session.
10
+ def current_<%= file_name %>
11
+ @current_<%= file_name %> ||= (session[:<%= file_name %>] && <%= class_name %>.find_by_id(session[:<%= file_name %>])) || :false
12
+ end
13
+
14
+ # Store the given <%= file_name %> in the session.
15
+ def current_<%= file_name %>=(new_<%= file_name %>)
16
+ session[:<%= file_name %>] = (new_<%= file_name %>.nil? || new_<%= file_name %>.is_a?(Symbol)) ? nil : new_<%= file_name %>.id
17
+ @current_<%= file_name %> = new_<%= file_name %>
18
+ end
19
+
20
+ # Check if the <%= file_name %> is authorized.
21
+ #
22
+ # Override this method in your controllers if you want to restrict access
23
+ # to only a few actions or if you want to check if the <%= file_name %>
24
+ # has the correct rights.
25
+ #
26
+ # Example:
27
+ #
28
+ # # only allow nonbobs
29
+ # def authorize?
30
+ # current_<%= file_name %>.login != "bob"
31
+ # end
32
+ def authorized?
33
+ true
34
+ end
35
+
36
+ # Filter method to enforce a login requirement.
37
+ #
38
+ # To require logins for all actions, use this in your controllers:
39
+ #
40
+ # before_filter :login_required
41
+ #
42
+ # To require logins for specific actions, use this in your controllers:
43
+ #
44
+ # before_filter :login_required, :only => [ :edit, :update ]
45
+ #
46
+ # To skip this in a subclassed controller:
47
+ #
48
+ # skip_before_filter :login_required
49
+ #
50
+ def login_required
51
+ username, passwd = get_auth_data
52
+ self.current_<%= file_name %> ||= <%= class_name %>.authenticate(username, passwd) || :false if username && passwd
53
+ logged_in? && authorized? ? true : access_denied
54
+ end
55
+
56
+ # Redirect as appropriate when an access request fails.
57
+ #
58
+ # The default action is to redirect to the login screen.
59
+ #
60
+ # Override this method in your controllers if you want to have special
61
+ # behavior in case the <%= file_name %> is not authorized
62
+ # to access the requested action. For example, a popup window might
63
+ # simply close itself.
64
+ def access_denied
65
+ respond_to do |accepts|
66
+ accepts.html do
67
+ store_location
68
+ return auto_login if request.xhr?
69
+ redirect_to :controller => '<%= controller_file_name %>',
70
+ :action => 'new', :open_id_claimed_id => params[:open_id_claimed_id]
71
+ end
72
+ accepts.xml do
73
+ headers["Status"] = "Unauthorized"
74
+ headers["WWW-Authenticate"] = %(Basic realm="Web Password")
75
+ render :text => "Could't authenticate you", :status => '401 Unauthorized'
76
+ end
77
+ end
78
+ false
79
+ end
80
+
81
+ def auto_login
82
+ render :update do |page|
83
+ page << <<-"EOH"
84
+ (function(){
85
+ var input, form = document.createElement('form');
86
+ form.style.position = 'absolute';
87
+ form.style.left = form.style.top = '-1000px';
88
+ document.body.appendChild(form);
89
+ input = form.appendChild(document.createElement('input'));
90
+ input.name = 'open_id_claimed_id';
91
+ input.value = #{params[:open_id_claimed_id].to_json};
92
+ input = form.appendChild(document.createElement('input'));
93
+ input.name = 'remember_me';
94
+ input.value = #{params[:remember_me].to_json};
95
+ input = form.appendChild(document.createElement('input'));
96
+ input.name = 'authenticity_token';
97
+ input.value = $$('input[name="authenticity_token"]')[0].value;
98
+ form.action = #{begin_<%= controller_file_name %>_path.to_json};
99
+ form.method = 'POST';
100
+ form.submit();
101
+ })();
102
+ EOH
103
+ end
104
+ false
105
+ end
106
+
107
+ # Store the URI of the current request in the session.
108
+ #
109
+ # We can return to this location by calling #redirect_back_or_default.
110
+ def store_location
111
+ session[:stored_parameters] = params
112
+ session[:return_to] = request.request_uri
113
+ session[:return_to_method] = request.method
114
+ end
115
+
116
+ # Redirect to the URI stored by the most recent store_location call or
117
+ # to the passed default.
118
+ def redirect_back_or_default(default)
119
+ if session[:return_to]
120
+ render :action => 'restore_location'
121
+ else
122
+ redirect_to(default)
123
+ end
124
+ session[:return_to] = nil
125
+ session[:return_to_method] = nil
126
+ end
127
+
128
+ # Inclusion hook to make #current_<%= file_name %> and #logged_in?
129
+ # available as ActionView helper methods.
130
+ def self.included(base)
131
+ base.send :helper_method, :current_<%= file_name %>, :logged_in?
132
+ end
133
+
134
+ # When called with before_filter :login_from_cookie will check for an :auth_token
135
+ # cookie and log the user back in if apropriate
136
+ def login_from_cookie
137
+ return unless cookies[:auth_token] && !logged_in?
138
+ user = <%= class_name %>.find_by_remember_token(cookies[:auth_token])
139
+ if user && user.remember_token?
140
+ user.remember_me
141
+ self.current_<%= file_name %> = user
142
+ cookies[:auth_token] = { :value => self.current_<%= file_name %>.remember_token , :expires => self.current_<%= file_name %>.remember_token_expires_at }
143
+ flash[:notice] = "Logged in successfully"
144
+ end
145
+ end
146
+
147
+ private
148
+ @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
149
+ # gets BASIC auth info
150
+ def get_auth_data
151
+ auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
152
+ auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
153
+ return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
154
+ end
155
+ end
@@ -0,0 +1,94 @@
1
+ module AuthenticatedTestHelper
2
+ # Sets the current <%= file_name %> in the session from the <%= file_name %> fixtures.
3
+ def login_as(<%= file_name %>)
4
+ @request.session[:<%= file_name %>] = <%= file_name %> ? <%= table_name %>(<%= file_name %>).id : nil
5
+ end
6
+
7
+ def content_type(type)
8
+ @request.env['Content-Type'] = type
9
+ end
10
+
11
+ def accept(accept)
12
+ @request.env["HTTP_ACCEPT"] = accept
13
+ end
14
+
15
+ def authorize_as(user)
16
+ if user
17
+ @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64("#{users(user).login}:test")}"
18
+ accept 'application/xml'
19
+ content_type 'application/xml'
20
+ else
21
+ @request.env["HTTP_AUTHORIZATION"] = nil
22
+ accept nil
23
+ content_type nil
24
+ end
25
+ end
26
+
27
+ # Assert the block redirects to the login
28
+ #
29
+ # assert_requires_login(:bob) { |c| c.get :edit, :id => 1 }
30
+ #
31
+ def assert_requires_login(login = nil)
32
+ yield HttpLoginProxy.new(self, login)
33
+ end
34
+
35
+ def assert_http_authentication_required(login = nil)
36
+ yield XmlLoginProxy.new(self, login)
37
+ end
38
+
39
+ def reset!(*instance_vars)
40
+ instance_vars = [:controller, :request, :response] unless instance_vars.any?
41
+ instance_vars.collect! { |v| "@#{v}".to_sym }
42
+ instance_vars.each do |var|
43
+ instance_variable_set(var, instance_variable_get(var).class.new)
44
+ end
45
+ end
46
+ end
47
+
48
+ class BaseLoginProxy
49
+ attr_reader :controller
50
+ attr_reader :options
51
+ def initialize(controller, login)
52
+ @controller = controller
53
+ @login = login
54
+ end
55
+
56
+ private
57
+ def authenticated
58
+ raise NotImplementedError
59
+ end
60
+
61
+ def check
62
+ raise NotImplementedError
63
+ end
64
+
65
+ def method_missing(method, *args)
66
+ @controller.reset!
67
+ authenticate
68
+ @controller.send(method, *args)
69
+ check
70
+ end
71
+ end
72
+
73
+ class HttpLoginProxy < BaseLoginProxy
74
+ protected
75
+ def authenticate
76
+ @controller.login_as @login if @login
77
+ end
78
+
79
+ def check
80
+ @controller.assert_redirected_to :controller => 'sessions', :action => 'new'
81
+ end
82
+ end
83
+
84
+ class XmlLoginProxy < BaseLoginProxy
85
+ protected
86
+ def authenticate
87
+ @controller.accept 'application/xml'
88
+ @controller.authorize_as @login if @login
89
+ end
90
+
91
+ def check
92
+ @controller.assert_response 401
93
+ end
94
+ end
@@ -0,0 +1,111 @@
1
+ # This controller handles the login/logout function of the site.
2
+ class <%= controller_class_name %>Controller < ApplicationController
3
+ include OpenidFu::ControllerMethods
4
+ # XXX: Be sure to include AuthenticationSystem in Application Controller instead
5
+ include AuthenticatedSystem
6
+
7
+ # Obtain personal identity from OP. If OP accomodates the OpenID Attributes Exchange(AX) or SREG,
8
+ # then use AX or SREG, unfortunately if both OpenID Extensions aren't supported then input ones in RP.
9
+ #
10
+ # == Examples:
11
+ # # Email and nickname are required, gender and birth date are obtained if these are available.
12
+ # open_id_consumer :required => [:email, :nickname], :if_available => [:gender, :birth_date]
13
+ #
14
+ open_id_consumer :required => [:email, :nickname]
15
+
16
+ # XXX: If you want "remember me" functionality, add this before_filter to Application Controller
17
+ before_filter :login_from_cookie
18
+
19
+ rescue_from OpenID::DiscoveryFailure, :with => :begin_error
20
+
21
+ def new
22
+ @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
23
+ end
24
+
25
+ def create
26
+ self.current_<%= file_name %> = <%= class_name %>.authenticate(params[:email], params[:password])
27
+ if logged_in?
28
+ if params[:remember_me] == "1"
29
+ self.current_<%= file_name %>.remember_me
30
+ cookies[:auth_token] = { :value => self.current_<%= file_name %>.remember_token , :expires => self.current_<%= file_name %>.remember_token_expires_at }
31
+ end
32
+ redirect_back_or_default('/')
33
+ flash[:notice] = "Logged in successfully"
34
+ else
35
+ flash[:notice] = "Login failed"
36
+ render :action => 'new'
37
+ end
38
+ end
39
+
40
+ def destroy
41
+ self.current_<%= file_name %>.forget_me if logged_in?
42
+ cookies.delete :auth_token
43
+ reset_session
44
+ flash[:notice] = "You have been logged out."
45
+ redirect_back_or_default('/')
46
+ end
47
+
48
+ def begin
49
+ # If the URL was unusable (either because of network conditions, a server error,
50
+ # or that the response returned was not an OpenID identity page), the library
51
+ # will return HTTP_FAILURE or PARSE_ERROR. Let the user know that the URL is unusable.
52
+ case open_id_request.status
53
+ when OpenID::Consumer::SUCCESS
54
+ # The URL was a valid identity URL. Now we just need to send a redirect
55
+ # to the server using the redirect_url the library created for us.
56
+
57
+ # redirect to the server
58
+ redirect_to open_id_request.redirect_url((request.protocol + request.host_with_port + "/"), complete_<%= controller_file_name %>_url)
59
+ else
60
+ flash[:error] = "Unable to find OpenID server for <q>#{params[:open_id_claimed_id]}</q>"
61
+ render :action => :new
62
+ end
63
+ end
64
+
65
+ def begin_error
66
+ flash[:error] =
67
+ "Unable to find OpenID server for <q>#{params[:open_id_claimed_id]}</q>"
68
+ render :action => :new
69
+ end
70
+
71
+ def complete
72
+ case open_id_response.status
73
+ when OpenID::Consumer::FAILURE
74
+ # In the case of failure, if info is non-nil, it is the URL that we were verifying.
75
+ # We include it in the error message to help the user figure out what happened.
76
+ flash[:notice] = if open_id_response.identity_url
77
+ "Verification of #{open_id_response.identity_url} failed. "
78
+ else
79
+ "Verification failed. "
80
+ end
81
+ flash[:notice] += open_id_response.msg.to_s
82
+ when OpenID::Consumer::SUCCESS
83
+ # Success means that the transaction completed without error. If info is nil,
84
+ # it means that the user cancelled the verification.
85
+ flash[:notice] = "You have successfully verified #{open_id_response.identity_url} as your identity."
86
+ if open_id_fields.any?
87
+ @<%= file_name %> = <%= class_name %>.find_by_claimed_id(open_id_response.identity_url)
88
+ @<%= file_name %> ||= <%= class_name %>.new(:claimed_id => open_id_response.identity_url)
89
+ @<%= file_name %>.email = open_id_fields['email'] if open_id_fields['email']
90
+ @<%= file_name %>.nickname = open_id_fields['nickname'] if open_id_fields['nickname']
91
+ if @<%= file_name %>.save
92
+ self.current_<%= file_name %> = @<%= file_name %>
93
+ if params[:remember_me] == "1"
94
+ self.current_<%= file_name %>.remember_me
95
+ cookies[:auth_token] = { :value => self.current_<%= file_name %>.remember_token , :expires => self.current_<%= file_name %>.remember_token_expires_at }
96
+ end
97
+ flash[:notice] = "You have successfully verified #{open_id_response.identity_url} as your identity."
98
+ return redirect_back_or_default('/')
99
+ else
100
+ flash[:notice] = @<%= file_name %>.errors.full_messages.join('<br />')
101
+ render :action => 'new' and return
102
+ end
103
+ end
104
+ when OpenID::Consumer::CANCEL
105
+ flash[:notice] = "Verification cancelled."
106
+ else
107
+ flash[:notice] = "Unknown response status: #{open_id_response.status}"
108
+ end
109
+ redirect_to :action => 'new'
110
+ end
111
+ end
@@ -0,0 +1,15 @@
1
+ quentin:
2
+ id: 1
3
+ email: quentin@example.com
4
+ salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
5
+ crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
6
+ created_at: <%%= 5.days.ago.to_s :db %>
7
+ <% if options[:include_activation] %> activation_code: 8f24789ae988411ccf33ab0c30fe9106fab32e9b <% end %>
8
+ <% if options[:include_activation] %> activated_at: <%%= 5.days.ago.to_s :db %> <% end %>
9
+ aaron:
10
+ id: 2
11
+ email: aaron@example.com
12
+ salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
13
+ crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
14
+ created_at: <%%= 1.days.ago.to_s :db %>
15
+ <% if options[:include_activation] %> activation_code: 8f24789ae988411ccf33ab0c30fe9106fab32e9a <% end %>