Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

the login loops is finished

  • Loading branch information...
commit 43d34d57a5070aa2c263263d28d0b867976c0518 1 parent 726a2a8
Chris Anderson authored
View
24 README
@@ -2,18 +2,18 @@ controllers
views
-/
- link to login/signup
- link to browse apps
-
-/login - this is the main page users see
- ability to signup or login
- params:
- email (shown from cookie if logged-in to appdrop)
- password
- -- (for signup)
- password confirmation
- nickname
+# /
+# link to login/signup
+# link to browse apps
+
+# /login - this is the main page users see
+# ability to signup or login
+# params:
+# email (shown from cookie if logged-in to appdrop)
+# password
+# -- (for signup)
+# password confirmation
+# nickname
/home
list of your apps
View
36 app/controllers/login_controller.rb
@@ -7,7 +7,7 @@ def login
key = /https?\:\/\/([\-a-z0-9]*)/.match(params[:continue])[1]
@app = App.find_by_key(key)
unless @app
- render :action => 'invalid'
+ render :action => 'invalid', :status => '404 Not Found'
return
end
end
@@ -28,8 +28,28 @@ def login
def authorize
key = /https?\:\/\/([\-a-z0-9]*)/.match(params[:continue])[1]
@app = App.find_by_key(key)
- raise unless @app
- redirect_to params[:continue]
+ unless @app
+ render :action => 'invalid', :status => '404 Not Found'
+ return
+ end
+ continue
+ end
+
+ def auth
+ @auth = AuthToken.find_by_token params[:token]
+ raise ActiveRecord::RecordNotFound unless @auth
+ key = /https?\:\/\/([\-a-z0-9]*)/.match(params[:app])[1]
+ @app = App.find_by_key(key)
+ if ((@app != @auth.app) || (@auth.used?))
+ render :text => "Invalid or Expired Token", :status => '403 Forbidden'
+ return
+ end
+ user = @auth.user
+ @auth.used = true
+ @auth.save
+ # todo - how do we know the app requesting it so we can do admin?
+ result = {:nickname => user.nickname, :email => user.email, :admin => (@app.user == @auth.user)}
+ render :json => result
end
def create
@@ -74,7 +94,15 @@ def continue
App.find_by_key(key)
end
if @app
- redirect_to params[:continue]
+ # setup create auth token and append it
+ @auth = AuthToken.create :user => current_user, :app => @app
+ url = URI.parse(params[:continue])
+ if url.query
+ url.query << "&auth=#{@auth.token}"
+ else
+ url.query = "auth=#{@auth.token}"
+ end
+ redirect_to url.to_s
else
redirect_back_or_default('/')
end
View
4 app/controllers/pages_controller.rb
@@ -1,7 +1,7 @@
class PagesController < ApplicationController
- def index
- @title = "Welcome"
+ def about
+ @title = "About AppDrop"
end
end
View
2  app/models/app.rb
@@ -11,6 +11,8 @@ class App < ActiveRecord::Base
validates_length_of :key, :in => (1..32)
validates_inclusion_of :port, :in => (3000..65535)
+ belongs_to :user
+
def initialize_configuration
make_app_dirs
create_portfile
View
9 app/models/auth_token.rb
@@ -0,0 +1,9 @@
+class AuthToken < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :app
+ validates_presence_of :user_id
+ validates_presence_of :app_id
+ validates_presence_of :token
+ include TokenGenerator
+ before_validation_on_create :set_token
+end
View
2  app/models/user.rb
@@ -23,6 +23,8 @@ class User < ActiveRecord::Base
# has_many :images, :as => :attachable
# composed_of :tz, :class_name => 'TZInfo::Timezone', :mapping => %w( time_zone time_zone )
+ validates_format_of :nickname, :with => /\A[\-a-z0-9A-Z\s]*\Z/
+ validates_format_of :email, :with => /^[_\w\d+-]+(\.[_\w\d-]+)*@[^\.@][\w\d\.-]+$/
validates_uniqueness_of :email, :case_sensitive => false
View
4 app/views/layouts/application.html.erb
@@ -8,8 +8,8 @@
<body>
<div id="container">
<div id="header">
- <h1>AppDrop<%= " | #{@title}" if @title %></h1>
- <% if flash[:notice] %><h3 id="flash"><%= flash[:notice] %></h3><% end %>
+ <h1><a href="/">AppDrop</a><%= " | #{@title}" if @title %></h1>
+ <% if false && flash[:notice] %><h3 id="flash"><%= flash[:notice] %></h3><% end %>
<% if current_user %>
<p>Hello <%= current_user %>. <%= link_to "You may click here to logout" %></p>
<% end %>
View
7 app/views/login/authorize.html.erb
@@ -2,6 +2,9 @@
<p>To login to <%= h @app.name %>, click "Authorize" and you will be redirected to the application.</p>
-<form action="/authorize?continue=<%= params[:continue] %>" method="post">
-<%= submit_tag "Authorize" %>
+<form action="/authorize" method="post">
+ <% if params[:continue] %>
+ <%= hidden_field_tag :continue, params[:continue] %>
+ <% end %>
+ <%= submit_tag "Authorize" %>
</form>
View
1  app/views/login/invalid.html.erb
@@ -0,0 +1 @@
+<h2>Sorry but <%= h params[:continue] %> is an invalid continue url.</h2>
View
3  app/views/login/login.html.erb
@@ -10,5 +10,8 @@
<p>New here? Please confirm your password and set a nickname, and you&apos;ll be on your way. If you already have an account, you can ignore those fields and just click "Continue."</p>
<%= f.password_field :password_confirmation %>
<%= f.text_field :nickname %>
+ <% if params[:continue] %>
+ <%= hidden_field_tag :continue, params[:continue] %>
+ <% end %>
<%= submit_tag "Continue" %>
<% end %>
View
1  app/views/pages/about.html.erb
@@ -0,0 +1 @@
+<h2>Just a little hack</h2>
View
3  app/views/pages/index.html.erb
@@ -1,3 +0,0 @@
-<h2>Host your <a href="http://appengine.google.com">Google AppEngine</a> applications.</h2>
-<p>Or you can <a href="/apps">browse</a> the <%= pluralize(App.count,'application') %> we already host.</p>
-<p><strong>Confidence builder:</strong> AppDrop is a proof-of-concept, made to show that the AppEngine platform released by Google is not closed, and could easily be supported by other hosts. Unlike Google&apos;s project, we make no claims to be able to scale beyond a small amount of traffic. In fact, at AppDrop we reserve the right to shut the whole thing down any time we feel like it. We're running on EC2, so <em>our virtual machine could just disappear at any time</em>. We hope you enjoy AppDrop. If we see enough demand, we might decided to make serious go at it. Only time will tell.</p>
View
1  config/routes.rb
@@ -39,6 +39,7 @@
:conditions => {:method => :delete}
map.connect '/authorize', :controller => 'login', :action => 'authorize'
+ map.connect '/auth', :controller => 'login', :action => 'auth'
# Install the default routes as the lowest priority.
# map.connect ':controller/:action/:id'
View
15 db/migrate/20080412232335_create_auth_tokens.rb
@@ -0,0 +1,15 @@
+class CreateAuthTokens < ActiveRecord::Migration
+ def self.up
+ create_table :auth_tokens do |t|
+ t.integer :user_id
+ t.integer :app_id
+ t.boolean :used, :default => false
+ t.string :token
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :auth_tokens
+ end
+end
View
11 db/schema.rb
@@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20080411060318) do
+ActiveRecord::Schema.define(:version => 20080412232335) do
create_table "apps", :force => true do |t|
t.integer "user_id"
@@ -23,6 +23,15 @@
add_index "apps", ["key"], :name => "index_apps_on_key"
add_index "apps", ["user_id"], :name => "index_apps_on_user_id"
+ create_table "auth_tokens", :force => true do |t|
+ t.integer "user_id"
+ t.integer "app_id"
+ t.boolean "used", :default => false
+ t.string "token"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "users", :force => true do |t|
t.string "nickname"
t.string "email"
View
3,981 log/development.log
0 additions, 3,981 deletions not shown
View
81 log/mongrel.log
@@ -1,81 +0,0 @@
-** Daemonized, any open files are closed. Look at log/mongrel.pid and log/mongrel.log for info.
-** Starting Mongrel listening at 0.0.0.0:3000
-/opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/tcphack.rb:12:in `initialize_without_backlog': Address already in use - bind(2) (Errno::EADDRINUSE)
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/tcphack.rb:12:in `initialize'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:560:in `new'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel.rb:560:in `initialize'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:128:in `new'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:128:in `listener'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:98:in `cloaker_'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:51:in `call'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:51:in `initialize'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:83:in `new'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:83:in `run'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/command.rb:211:in `run'
- from /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:243
- from /opt/local/bin/mongrel_rails:16:in `load'
- from /opt/local/bin/mongrel_rails:16
-** Daemonized, any open files are closed. Look at log/mongrel.pid and log/mongrel.log for info.
-** Starting Mongrel listening at 0.0.0.0:3001
-** Starting Rails with development environment...
-** Rails loaded.
-** Loading any Rails specific GemPlugins
-** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart).
-** Rails signals registered. HUP => reload (without restart). It might not work well.
-** Mongrel available at 0.0.0.0:3001
-** Writing PID file to log/mongrel.pid
-** USR2 signal received.
-** Restarting with arguments: ruby /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails start -p 3001 -d
-** Daemonized, any open files are closed. Look at log/mongrel.pid and log/mongrel.log for info.
-** Starting Mongrel listening at 0.0.0.0:3001
-** Starting Rails with development environment...
-** Rails loaded.
-** Loading any Rails specific GemPlugins
-** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart).
-** Rails signals registered. HUP => reload (without restart). It might not work well.
-** Mongrel available at 0.0.0.0:3001
-** Writing PID file to log/mongrel.pid
-** USR2 signal received.
-** Restarting with arguments: ruby /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails start -p 3001 -d
-** Daemonized, any open files are closed. Look at log/mongrel.pid and log/mongrel.log for info.
-** Starting Mongrel listening at 0.0.0.0:3001
-** Starting Rails with development environment...
-** Rails loaded.
-** Loading any Rails specific GemPlugins
-** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart).
-** Rails signals registered. HUP => reload (without restart). It might not work well.
-** Mongrel available at 0.0.0.0:3001
-** Writing PID file to log/mongrel.pid
-** USR2 signal received.
-** Restarting with arguments: ruby /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails start -p 3001 -d
-** Daemonized, any open files are closed. Look at log/mongrel.pid and log/mongrel.log for info.
-** Starting Mongrel listening at 0.0.0.0:3001
-** Starting Rails with development environment...
-** Rails loaded.
-** Loading any Rails specific GemPlugins
-** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart).
-** Rails signals registered. HUP => reload (without restart). It might not work well.
-** Mongrel available at 0.0.0.0:3001
-** Writing PID file to log/mongrel.pid
-** USR2 signal received.
-** Restarting with arguments: ruby /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails start -p 3001 -d
-** Daemonized, any open files are closed. Look at log/mongrel.pid and log/mongrel.log for info.
-** Starting Mongrel listening at 0.0.0.0:3001
-** Starting Rails with development environment...
-** Rails loaded.
-** Loading any Rails specific GemPlugins
-** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart).
-** Rails signals registered. HUP => reload (without restart). It might not work well.
-** Mongrel available at 0.0.0.0:3001
-** Writing PID file to log/mongrel.pid
-** USR2 signal received.
-** Restarting with arguments: ruby /opt/local/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails start -p 3001 -d
-** Daemonized, any open files are closed. Look at log/mongrel.pid and log/mongrel.log for info.
-** Starting Mongrel listening at 0.0.0.0:3001
-** Starting Rails with development environment...
-** Rails loaded.
-** Loading any Rails specific GemPlugins
-** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart).
-** Rails signals registered. HUP => reload (without restart). It might not work well.
-** Mongrel available at 0.0.0.0:3001
-** Writing PID file to log/mongrel.pid
View
2  log/mongrel.pid
@@ -1 +1 @@
-5325
+13337
View
26,372 log/test.log
0 additions, 26,372 deletions not shown
View
72 protocol.txt
@@ -0,0 +1,72 @@
+basic process:
+
+fug-this links to google login page, user sumbits login form to google url.
+google submit url redirects to login service on fug-this, with a long auth key.
+*the fug-this login service presumably does a background call to goole to get the user info with which to set the cookies.*
+on the setting-cookie response, the fug-this service also redirects to the continue url.
+
+
+in dev mode
+
+fug this links to the login page on its own domain, which sets the cookie (unauthenticated) on submit and redirects back to the continue url...
+
+
+MY INSECURE AUTH PROTOCOL
+
+login link (or maybe it is easier to leave this alone and set the current version of it (_ah/login) to redirect to appdrop.com/login)?
+
+http://appdrop.com/login?continue=http://myapp.appdrop.com/_ah/login%3Fcontinue%3Dhttp://myapp.appdrop.com/
+
+draws form that submits to
+
+http://appdrop.com/login or http://appdrop.com/authorize with continue as a hidden field
+
+the form reciever redirects to
+
+http://myapp.appdrop.com/_ah/login?continue=http://myapp.appdrop.com/&auth=878this7is23my37expiring2unique4token
+
+
+which only has to query appdrop with that auth token to get the user info {email, nickname}
+
+http://appdrop.com/token?auth=878this7is23my37expiring2unique4token
+
+which it uses to set the session cookie (this cookie needs to be tamperproof like rails, and feed into the User() service to work with the google-style API).
+
+logout link
+http://myapp.appdrop.com/_ah/logout?continue=http://myapp.appdrop.com/
+this is simple all it does is clear the session cookie.
+
+
+login process urls
+
+
+login link:
+
+https://www.google.com/accounts/ServiceLogin?service=ah&continue=http://fug-this.appspot.com/_ah/login%3Fcontinue%3Dhttp://fug-this.appspot.com/&ltmpl=gm&ahname=Fug+This&sig=807c87be37eb988d2f31e49df31eec42
+
+submit:
+
+https://www.google.com/accounts/CheckCookie?continue=http%3A%2F%2Ffug-this.appspot.com%2F_ah%2Flogin%3Fcontinue%3Dhttp%3A%2F%2Ffug-this.appspot.com%2F&service=ah&chtml=LoginDoneHtml&sig=ae4756a21635ca68ba30502782128042
+
+redirect to: (maybe...)
+
+http://fug-this.appspot.com/_ah/login?continue=http://fug-this.appspot.com/&auth=DQAAAJMAAABGTctmtwe8silIW5aWbC74pTudJx3h9FI9Jl3irco9doE9gIVrHpqiNlvfFPDN9hEbzfJ3QQZYAZLxaiee8_4Nsr8DdZfS0HWa92FeJyBTiqhQBr6Ob_35XgAs7nuFVQE5cwybv8eC_fRp2LVxQdNXMR1oUofmkLMJ3tzAuq14zo1cguS4I45yFxmpVMSQCu73mgNEcLzzrFiUzIJKN9jM
+
+final url (http://fug-this.appspot.com/)
+
+
+logout urls
+
+logout link:
+
+http://fug-this.appspot.com/_ah/logout?continue=https://www.google.com/accounts/Logout%3Fcontinue%3Dhttp://fug-this.appspot.com/%26service%3Dah
+
+redirect via
+
+https://www.google.com/accounts/Logout?continue=http://fug-this.appspot.com/&service=ah
+
+http://www.google.com/accounts/Logout2?service=ah&ilo=1&ils=cl%2Cpages%2Cmail&ilc=0&continue=http%3A%2F%2Ffug-this.appspot.com%2F&zx=-63457890
+
+http://www.google.com/accounts/Logout2?service=ah&ilo=1&ils=cl&ilc=0&continue=http%3A%2F%2Ffug-this.appspot.com%2F&zx=889321816
+
+final url (http://fug-this.appspot.com/)
View
3  public/index.html
@@ -17,6 +17,9 @@
<p>Or you can <a href="/apps">browse the applications</a> we already host.</p>
<p><strong>Confidence builder:</strong> AppDrop is a proof-of-concept, made to show that the AppEngine platform released by Google is not closed, and could easily be supported by other hosts. Unlike Google&apos;s project, we make no claims to be able to scale beyond a small amount of traffic. In fact, at AppDrop we reserve the right to shut the whole thing down any time we feel like it. We're running on EC2, so <em>our virtual machine could just disappear at any time</em>. We hope you enjoy AppDrop. If we see enough demand, we might decided to make serious go at it. Only time will tell.</p>
+<h2><em>Lock in, we don&apos;t need no stinking lock in!</em></h2>
+<p><strong>Use at your own risk!</strong> Our current implementation makes no claims to be a finished product. For that reason, we&apos;re doing the simplest thing that could possibly work on most fronts. This means that we&apos;ve pretty much ignored security concerns, so for the time being please don&apos;t upload any applications that deal in sensitive data. Also, we&apos;ve yet to enable email support. This application and the EC2 Image that support it will be released for you to play with soon enough, so if email support, database scaling, or more secure logins are important to you, you&apos;ll have the opportunity to implement them yourself.</p>
+<p>Hacked together by <a href="http://jchris.mfdz.com">Chris Anderson</a> with moral support from <a href="http://bottlecaplabs.net/">Bottlecap Labs</a>.</p>
</div>
</body>
</html>
View
92 spec/controllers/login_controller_spec.rb
@@ -76,14 +76,71 @@ def do_get
describe LoginController, "POST /authorize while logged in with app info" do
before(:each) do
- @user = mock_model(User)
+ @user = mock_user
controller.stub!(:current_user).and_return @user
@app = mock_model(App)
App.stub!(:find_by_key).and_return(@app)
+ @auth = mock_model(AuthToken, :token => 'authtoken')
+ AuthToken.stub!(:create).and_return(@auth)
+ end
+ it "should create an auth token" do
+ AuthToken.should_receive(:create).with(:user => @user, :app => @app).and_return(@auth)
+ post :authorize, :continue => "http://not-fug-this.appspot.com/_ah/login"
end
it "should redirect to the app continue page" do
- post :authorize, :continue => "http://not-fug-this.appspot.com/_ah/login%3Fcontinue%3Dhttp://not-fug-this.appspot.com/"
- response.should redirect_to('http://not-fug-this.appspot.com/_ah/login%3Fcontinue%3Dhttp://not-fug-this.appspot.com/')
+ post :authorize, :continue => "http://not-fug-this.appspot.com/_ah/login"
+ response.should redirect_to('http://not-fug-this.appspot.com/_ah/login?auth=authtoken')
+ end
+end
+
+describe LoginController, "GET /auth?token=validtoken" do
+ before(:each) do
+ @auth = mock_model(AuthToken, :used? => false, :used= => true, :save => true, :token => 'validtoken', :user => @u1 = mock_user, :app => @app = mock_model(App, :user => @u2 = mock_model(User)))
+ AuthToken.stub!(:find_by_token).and_return(@auth)
+ App.stub!(:find_by_key).and_return(@app)
+ end
+ it "should find the token" do
+ AuthToken.should_receive(:find_by_token).with('validtoken').and_return(@auth)
+ get :auth, :token => 'validtoken', :app => 'http://myapp.appdrop.com/'
+ end
+ it "should return json of the user" do
+ get :auth, :token => 'validtoken', :app => 'http://myapp.appdrop.com/'
+ response.body.should match(/flappy/)
+ response.body.should match(/false/)
+ end
+ it "should say admin yes if the user owns the app" do
+ @app.stub!(:user).and_return(@u1)
+ get :auth, :token => 'validtoken', :app => 'http://myapp.appdrop.com/'
+ response.body.should match(/true/)
+ end
+ it "should mark the token used" do
+ @auth.should_receive(:used=).with(true)
+ get :auth, :token => 'validtoken', :app => 'http://myapp.appdrop.com/'
+ end
+end
+
+describe LoginController, "GET /auth?token=usedtoken&app=http://myapp.appdrop.com/" do
+ before(:each) do
+ @auth = mock_model(AuthToken, :used? => true, :used= => true, :save => true, :token => 'validtoken', :user => mock_user, :app => @app = mock_model(App))
+ AuthToken.stub!(:find_by_token).and_return(@auth)
+ App.stub!(:find_by_key).and_return(@app)
+ end
+ it "should barf" do
+ get :auth, :token => 'validtoken', :app => 'http://myapp.appdrop.com/'
+ response.should_not be_success
+ end
+end
+
+describe LoginController, "GET /auth?token=wrongapp&app=http://myapp.appdrop.com/" do
+ before(:each) do
+ @auth = mock_model(AuthToken, :used? => false, :used= => true, :save => true, :token => 'validtoken', :user => mock_user, :app => @app = mock_model(App))
+ AuthToken.stub!(:find_by_token).and_return(@auth)
+ @app2 = mock_model(App)
+ App.stub!(:find_by_key).and_return(@app2)
+ end
+ it "should barf" do
+ get :auth, :token => 'wrongapp', :app => 'http://myapp.appdrop.com/'
+ response.should_not be_success
end
end
@@ -94,9 +151,8 @@ def do_get
App.stub!(:find_by_key).and_return(nil)
end
it "should barf" do
- lambda do
- post :authorize, :continue => "http://not-fug-this.appspot.com/_ah/login%3Fcontinue%3Dhttp://not-fug-this.appspot.com/"
- end.should raise_error
+ post :authorize, :continue => "http://not-fug-this.appspot.com/_ah/login%3Fcontinue%3Dhttp://not-fug-this.appspot.com/"
+ response.should_not be_success
end
end
@@ -106,8 +162,10 @@ def do_get
@user = mock_user
User.stub!(:authenticate).and_return(@user)
controller.stub!(:logged_in?).and_return(true)
- @app = mock_model(App)
+ @app = mock_model(App, :valid? => true)
App.stub!(:find_by_key).and_return(@app)
+ @auth = mock_model(AuthToken, :token => 'authtoken')
+ AuthToken.stub!(:create).and_return(@auth)
end
it 'should authenticate user' do
@@ -125,7 +183,7 @@ def do_get
response.cookies["auth_token"].should be_nil
end
- it "should redirect to root" do
+ it "should redirect to root without app params" do
post :create, :user => {}
response.should redirect_to('http://test.host/')
end
@@ -134,9 +192,13 @@ def do_get
App.should_receive(:find_by_key).with('myapp').and_return(@app)
post :create, :continue => 'http://myapp.appdrop.com/continue', :user => {}
end
- it "should redirect to the app" do
- post :create, :continue => 'http://myapp.appdrop.com/continue', :user => {}
- response.should redirect_to('http://myapp.appdrop.com/continue')
+ it "should redirect to the app with auth token" do
+ post :create, :continue => "http://myapp.appdrop.com/login?continue=http://myapp.appdrop.com/", :user => {}
+ response.should redirect_to("http://myapp.appdrop.com/login?continue=http://myapp.appdrop.com/&auth=#{@auth.token}")
+ end
+ it "should create an auth token" do
+ AuthToken.should_receive(:create).with(:user => @user, :app => @app).and_return(@auth)
+ post :create, :continue => "http://myapp.appdrop.com/login?continue=http://myapp.appdrop.com/", :user => {}
end
end
@@ -179,14 +241,16 @@ def do_post
end
describe "when the user saves and there is app info" do
before(:each) do
- @user = mock_model(User, :to_param => "1", :save => true)
+ @user = mock_user
User.stub!(:new).and_return(@user)
- @app = mock_model(App)
+ @app = mock_model(App, :valid? => true)
App.stub!(:find_by_key).and_return(@app)
+ @auth = mock_model(AuthToken, :token => 'authtoken')
+ AuthToken.stub!(:create).and_return(@auth)
end
it "should redirect to the app continue" do
post :create, :user => {:email => 'user@example.com', :password => 'password', :password_confirmation => 'password', :nickname => 'user'}, :continue => 'http://example.appdrop.com'
- response.should redirect_to('http://example.appdrop.com')
+ response.should redirect_to("http://example.appdrop.com?auth=#{@auth.token}")
end
end
describe "when the user wont save (invalid)" do
View
7 spec/fixtures/auth_tokens.yml
@@ -0,0 +1,7 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+# one:
+# column: value
+#
+# two:
+# column: value
View
11 spec/models/auth_token_spec.rb
@@ -0,0 +1,11 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe AuthToken do
+ before(:each) do
+ @auth_token = AuthToken.new :user_id => 1, :app_id => 1
+ end
+
+ it "should be valid" do
+ @auth_token.save.should be_true
+ end
+end
View
15 spec/spec_helper.rb
@@ -15,13 +15,14 @@
config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
- def mock_user
- user = mock_model(User,
- :id => 1,
- :login => 'flappy',
- :email => 'flappy@email.com',
- :password => '', :password_confirmation => ''
- )
+ def mock_user(params = {})
+ params.merge!({:id => 1,
+ :nickname => 'mr flappy',
+ :email => 'flappy@email.com',
+ :password => '', :password_confirmation => '',
+ :valid? => true,
+ :save => true})
+ mock_model(User, params)
end
# == Fixtures
View
29 vendor/plugins/token_generator/README
@@ -0,0 +1,29 @@
+TokenGenerator
+==============
+
+Mix-in for classes that needs to have a token generated using MD5. You can set the length of the token
+and provide it with an optional block that'll check the validity of the generated token (usually whether it's
+already taken or not).
+
+The two methods are generate_token, which will just return a new token, and set_token, which will assume
+that there's a writer for the instance variable "token" and that the class has a "find_by_token" method to check
+validity (if a duplicate exists, generate another token).
+
+Examples:
+
+ class Invitation < ActiveRecord::Base
+ include TokenGenerator
+ before_create :set_token
+ end
+
+ class ImperialInvitation < ActiveRecord::Base
+ include TokenGenerator
+ before_create :set_token
+
+ private
+ def set_token
+ self.token = generate_token { |token| complies_to_imperial_standards?(token) }
+ end
+ end
+
+Copyright (c) 2005 David Heinemeier Hansson, Marcel Molina Jr. released under the MIT license
View
15 vendor/plugins/token_generator/lib/token_generator.rb
@@ -0,0 +1,15 @@
+module TokenGenerator
+ def generate_token(size = 12, &validity)
+ constant = "#{self.class.name}#{id}"
+
+ begin
+ token = CGI::Session.generate_unique_id(constant).first(size)
+ end while !validity.call(token) if block_given?
+
+ token
+ end
+
+ def set_token
+ self.token = generate_token { |token| self.class.find_by_token(token).nil? }
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.