openid_fu_generator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 %>