mbleigh-twitter-auth 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,52 @@
1
+ TwitterAuth
2
+ ===========
3
+
4
+ TwitterAuth is a plugin to provide a standard authentication stack using Twitter
5
+ as an SSO provider. This is obviously most useful and therefore targeted at
6
+ apps that intend to heavily use the Twitter API.
7
+
8
+ **Note:** TwitterAuth uses Rails Engines functionality from Rails 2.3 and is
9
+ therefore incompatible with earlier versions of Rails.
10
+
11
+ Getting Started
12
+ ---------------
13
+
14
+ First, install either by gem or by plugin:
15
+
16
+ config.gem 'mbleigh-twitter-auth', :source => 'http://gems.github.com/'
17
+
18
+ OR
19
+
20
+ script/plugin install git://github.com/mbleigh/twitter-auth.git
21
+
22
+ Next, to get started, you will need to generate the migration for the User
23
+ model that TwitterAuth uses. It's simple:
24
+
25
+ script/generate migration twitter_auth_migration
26
+
27
+ If you look in the migration you will see that there are some information
28
+ fields pre-populated (name, location, etc). These will automatically be
29
+ retrieved from Twitter at each login and therefor kept both accessible
30
+ and fresh for your usage.
31
+
32
+ Believe it or not, that's it! You now have access to the standard suite
33
+ of restful-auth controller helpers such as:
34
+
35
+ * login_required
36
+ * current_user
37
+ * logged_in?
38
+
39
+ And you also have the ability to login through the built-in SessionController.
40
+ Just run the app and point your browser to '/login' to get started! You don't
41
+ need to sign up because it will automatically create new users if the logging
42
+ in user has never logged in before.
43
+
44
+ Caveats
45
+ -------
46
+
47
+ This is **extremely alpha** code and has not been thoroughly spec'ed or even
48
+ inspected. Use at your own risk as the functionality is likely to change
49
+ drastically even in the near future.
50
+
51
+
52
+ Copyright (c) 2009 [Michael Bleigh](http://www.mbleigh.com) and [Intridea, Inc.](http://www.intridea.com/), released under the MIT license
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
@@ -0,0 +1,24 @@
1
+ class TwitterAuthMigration < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :users do |t|
4
+ t.string :login
5
+ t.string :crypted_password
6
+ t.string :salt
7
+
8
+ # Basic info pulled automatically from Twitter.
9
+ # Feel free to remove any of these columns you don't want.
10
+ t.string :name
11
+ t.string :location
12
+ t.text :description
13
+ t.string :profile_image_url
14
+ t.string :url
15
+ t.boolean :protected
16
+
17
+ t.timestamps
18
+ end
19
+ end
20
+
21
+ def self.down
22
+ drop_table :users
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ class TwitterAuthMigrationGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => "twitter_auth_migration"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module TwitterAuth
2
+ class Error < StandardError; end
3
+ end
4
+
5
+ require 'twitter_auth/controller_extensions'
@@ -0,0 +1,200 @@
1
+ module TwitterAuth
2
+ # The extensions to ActionController to enable our
3
+ # usage of Twitter-based authentication. This is
4
+ # taken directly from restful-authentication, so
5
+ # no credit is due here.
6
+ module ControllerExtensions
7
+ # Returns true or false if the user is logged in.
8
+ # Preloads @current_user with the user model if they're logged in.
9
+ def logged_in?
10
+ !!current_user
11
+ end
12
+
13
+ # Accesses the current user from the session.
14
+ # Future calls avoid the database because nil is not equal to false.
15
+ def current_user
16
+ @current_user ||= (login_from_session || login_from_basic_auth) unless @current_user == false
17
+ end
18
+
19
+ # Store the given user id in the session.
20
+ def current_user=(new_user)
21
+ session[:user_id] = new_user ? new_user.id : nil
22
+ @current_user = new_user || false
23
+ end
24
+
25
+ # Check if the user is authorized
26
+ #
27
+ # Override this method in your controllers if you want to restrict access
28
+ # to only a few actions or if you want to check if the user
29
+ # has the correct rights.
30
+ #
31
+ # Example:
32
+ #
33
+ # # only allow nonbobs
34
+ # def authorized?
35
+ # current_user.login != "bob"
36
+ # end
37
+ #
38
+ def authorized?(action=nil, resource=nil, *args)
39
+ logged_in?
40
+ end
41
+
42
+ # Filter method to enforce a login requirement.
43
+ #
44
+ # To require logins for all actions, use this in your controllers:
45
+ #
46
+ # before_filter :login_required
47
+ #
48
+ # To require logins for specific actions, use this in your controllers:
49
+ #
50
+ # before_filter :login_required, :only => [ :edit, :update ]
51
+ #
52
+ # To skip this in a subclassed controller:
53
+ #
54
+ # skip_before_filter :login_required
55
+ #
56
+ def login_required
57
+ authorized? || access_denied
58
+ end
59
+
60
+ # Redirect as appropriate when an access request fails.
61
+ #
62
+ # The default action is to redirect to the login screen.
63
+ #
64
+ # Override this method in your controllers if you want to have special
65
+ # behavior in case the user is not authorized
66
+ # to access the requested action. For example, a popup window might
67
+ # simply close itself.
68
+ def access_denied
69
+ respond_to do |format|
70
+ format.html do
71
+ store_location
72
+ redirect_to new_session_path
73
+ end
74
+ # format.any doesn't work in rails version < http://dev.rubyonrails.org/changeset/8987
75
+ # you may want to change format.any to e.g. format.any(:js, :xml)
76
+ format.any(:xml, :json) do
77
+ request_http_basic_authentication 'Web Password'
78
+ end
79
+ end
80
+ end
81
+
82
+ # Store the URI of the current request in the session.
83
+ #
84
+ # We can return to this location by calling #redirect_back_or_default.
85
+ def store_location
86
+ session[:return_to] = request.request_uri
87
+ end
88
+
89
+ # Redirect to the URI stored by the most recent store_location call or
90
+ # to the passed default. Set an appropriately modified
91
+ # after_filter :store_location, :only => [:index, :new, :show, :edit]
92
+ # for any controller you want to be bounce-backable.
93
+ def redirect_back_or_default(default=nil)
94
+ redirect_to(session[:return_to] || default || default_location)
95
+ session[:return_to] = nil
96
+ end
97
+
98
+ # Override this method with what you want your 'default default'
99
+ # to be (where it will redirect if there's no back and no explicit
100
+ # default).
101
+ def default_location
102
+ '/'
103
+ end
104
+
105
+ # Inclusion hook to make #current_user and #logged_in?
106
+ # available as ActionView helper methods.
107
+ def self.included(base)
108
+ base.send :helper_method, :current_user, :logged_in?, :authorized? if base.respond_to? :helper_method
109
+ end
110
+
111
+ #
112
+ # Login
113
+ #
114
+
115
+ # Called from #current_user. First attempt to login by the user id stored in the session.
116
+ def login_from_session
117
+ self.current_user = User.find_by_id(session[:user_id]) if session[:user_id]
118
+ end
119
+
120
+ # Called from #current_user. Now, attempt to login by basic authentication information.
121
+ def login_from_basic_auth
122
+ authenticate_with_http_basic do |login, password|
123
+ self.current_user = User.authenticate(login, password)
124
+ end
125
+ end
126
+
127
+ #
128
+ # Logout
129
+ #
130
+
131
+ # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
132
+ # for the paranoid: we _should_ be storing user_token = hash(cookie_token, request IP)
133
+ # def login_from_cookie
134
+ # user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token])
135
+ # if user && user.remember_token?
136
+ # self.current_user = user
137
+ # handle_remember_cookie! false # freshen cookie token (keeping date)
138
+ # self.current_user
139
+ # end
140
+ # end
141
+
142
+ # This is ususally what you want; resetting the session willy-nilly wreaks
143
+ # havoc with forgery protection, and is only strictly necessary on login.
144
+ # However, **all session state variables should be unset here**.
145
+ def logout_keeping_session!
146
+ # Kill server-side auth cookie
147
+ @current_user.forget_me if @current_user.is_a? User
148
+ @current_user = false # not logged in, and don't do it for me
149
+ # kill_remember_cookie! # Kill client-side auth cookie
150
+ session[:user_id] = nil # keeps the session but kill our variable
151
+ # explicitly kill any other session variables you set
152
+ end
153
+
154
+ # The session should only be reset at the tail end of a form POST --
155
+ # otherwise the request forgery protection fails. It's only really necessary
156
+ # when you cross quarantine (logged-out to logged-in).
157
+ def logout_killing_session!
158
+ logout_keeping_session!
159
+ reset_session
160
+ end
161
+
162
+ #
163
+ # Remember_me Tokens
164
+ #
165
+ # Cookies shouldn't be allowed to persist past their freshness date,
166
+ # and they should be changed at each login
167
+
168
+ # Cookies shouldn't be allowed to persist past their freshness date,
169
+ # and they should be changed at each login
170
+
171
+ # def valid_remember_cookie?
172
+ # return nil unless @current_user
173
+ # (@current_user.remember_token?) &&
174
+ # (cookies[:auth_token] == @current_user.remember_token)
175
+ # end
176
+
177
+ # Refresh the cookie auth token if it exists, create it otherwise
178
+ # def handle_remember_cookie! new_cookie_flag
179
+ # return unless @current_user
180
+ # case
181
+ # when valid_remember_cookie? then @current_user.refresh_token # keeping same expiry date
182
+ # when new_cookie_flag then @current_user.remember_me
183
+ # else @current_user.forget_me
184
+ # end
185
+ # send_remember_cookie!
186
+ # end
187
+ #
188
+ # def kill_remember_cookie!
189
+ # cookies.delete :auth_token
190
+ # end
191
+ #
192
+ # def send_remember_cookie!
193
+ # cookies[:auth_token] = {
194
+ # :value => @current_user.remember_token,
195
+ # :expires => @current_user.remember_token_expires_at }
196
+ # end
197
+ end
198
+ end
199
+
200
+ ActionController::Base.send :include, TwitterAuth::ControllerExtensions
@@ -0,0 +1,28 @@
1
+ require 'openssl'
2
+ module TwitterAuth
3
+ module Cryptify
4
+ class Error < StandardError; end
5
+ mattr_accessor :crypt_password
6
+ @@crypt_password = '--TwitterAuth-!##@--2ef'
7
+
8
+ def self.encrypt(data, salt)
9
+ cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
10
+ cipher.encrypt
11
+ cipher.pkcs5_keyivgen(crypt_password, salt)
12
+ encrypted_data = cipher.update(data)
13
+ encrypted_data << cipher.final
14
+ end
15
+
16
+ def self.decrypt(encrypted_data, salt)
17
+ cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
18
+ cipher.decrypt
19
+ cipher.pkcs5_keyivgen(crypt_password, salt)
20
+ data = cipher.update(encrypted_data)
21
+ data << cipher.final
22
+ end
23
+
24
+ def self.generate_salt
25
+ [rand(2**64 - 1)].pack("Q")
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ begin
2
+ require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
3
+ rescue LoadError
4
+ puts "You need to install rspec in your base app"
5
+ exit
6
+ end
7
+
8
+ plugin_spec_dir = File.dirname(__FILE__)
9
+ ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
10
+
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'twitter_auth'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class TwitterAuthTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mbleigh-twitter-auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Bleigh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-06 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: TODO
17
+ email: michael@intridea.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README.markdown
26
+ - VERSION.yml
27
+ - generators/twitter_auth_migration
28
+ - generators/twitter_auth_migration/templates
29
+ - generators/twitter_auth_migration/templates/migration.rb
30
+ - generators/twitter_auth_migration/twitter_auth_migration_generator.rb
31
+ - lib/twitter_auth
32
+ - lib/twitter_auth/controller_extensions.rb
33
+ - lib/twitter_auth/cryptify.rb
34
+ - lib/twitter_auth.rb
35
+ - test/test_helper.rb
36
+ - test/twitter_auth_test.rb
37
+ - spec/spec_helper.rb
38
+ - spec/twitter_auth_spec.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/mbleigh/twitter-auth
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --inline-source
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: Standard authentication stack for Rails using Twitter to log in.
66
+ test_files: []
67
+