Merging 16820:16891 from trunk.
authorMatt Amos <zerebubuth@gmail.com>
Thu, 6 Aug 2009 16:24:39 +0000 (16:24 +0000)
committerMatt Amos <zerebubuth@gmail.com>
Thu, 6 Aug 2009 16:24:39 +0000 (16:24 +0000)
86 files changed:
app/controllers/application_controller.rb
app/controllers/changeset_controller.rb
app/controllers/node_controller.rb
app/controllers/oauth_clients_controller.rb [new file with mode: 0644]
app/controllers/oauth_controller.rb [new file with mode: 0644]
app/controllers/relation_controller.rb
app/controllers/trace_controller.rb
app/controllers/user_controller.rb
app/controllers/user_preference_controller.rb
app/controllers/way_controller.rb
app/helpers/oauth_clients_helper.rb [new file with mode: 0644]
app/helpers/oauth_helper.rb [new file with mode: 0644]
app/models/access_token.rb [new file with mode: 0644]
app/models/client_application.rb [new file with mode: 0644]
app/models/oauth_nonce.rb [new file with mode: 0644]
app/models/oauth_token.rb [new file with mode: 0644]
app/models/request_token.rb [new file with mode: 0644]
app/models/user.rb
app/views/oauth/authorize_failure.html.erb [new file with mode: 0644]
app/views/oauth/authorize_success.html.erb [new file with mode: 0644]
app/views/oauth/oauthorize.html.erb [new file with mode: 0644]
app/views/oauth_clients/_form.html.erb [new file with mode: 0644]
app/views/oauth_clients/edit.html.erb [new file with mode: 0644]
app/views/oauth_clients/index.html.erb [new file with mode: 0644]
app/views/oauth_clients/new.html.erb [new file with mode: 0644]
app/views/oauth_clients/not_found.erb [new file with mode: 0644]
app/views/oauth_clients/show.html.erb [new file with mode: 0644]
app/views/user/account.html.erb
app/views/user/view.html.erb
config/environment.rb
config/locales/de.yml
config/locales/en.yml
config/routes.rb
db/migrate/039_create_oauth_tables.rb [new file with mode: 0644]
db/migrate/040_add_fine_o_auth_permissions.rb [new file with mode: 0644]
db/migrate/041_add_foreign_keys_to_oauth_tables.rb [new file with mode: 0644]
test/fixtures/client_applications.yml [new file with mode: 0644]
test/integration/client_application_test.rb [new file with mode: 0644]
test/test_helper.rb
test/unit/oauth_nonce_test.rb [new file with mode: 0644]
test/unit/oauth_token_test.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/.gitignore [new file with mode: 0644]
vendor/plugins/oauth-plugin/CHANGELOG [new file with mode: 0644]
vendor/plugins/oauth-plugin/MIT-LICENSE [new file with mode: 0644]
vendor/plugins/oauth-plugin/README.rdoc [new file with mode: 0644]
vendor/plugins/oauth-plugin/Rakefile [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/USAGE [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/oauth_provider_generator.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/_form.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/access_token.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize_failure.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize_success.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application_spec.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application_test.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_applications.yml [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller_spec.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller_test.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_helper.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_spec.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_spec_helper.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_test.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_test_helper.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/edit.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/helper.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/index.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/migration.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/new.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce_spec.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce_test.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonces.yml [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token_spec.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token_test.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_tokens.yml [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/request_token.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/generators/oauth_provider/templates/show.html.erb [new file with mode: 0644]
vendor/plugins/oauth-plugin/init.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/install.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/lib/oauth/rails/controller_methods.rb [new file with mode: 0644]
vendor/plugins/oauth-plugin/tasks/oauth_tasks.rake [new file with mode: 0644]
vendor/plugins/oauth-plugin/uninstall.rb [new file with mode: 0644]

index 2093a959c85af202b2d4a4dfce420578f65489c9..6dbe9165ca2593b20f5fff3c7e6c46f7469016e6 100644 (file)
@@ -22,19 +22,61 @@ class ApplicationController < ActionController::Base
     redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri unless @user
   end
 
+  ##
+  # requires the user to be logged in by the token or HTTP methods, or have an 
+  # OAuth token with the right capability. this method is a bit of a pain to call 
+  # directly, since it's cumbersome to call filters with arguments in rails. to
+  # make it easier to read and write the code, there are some utility methods
+  # below.
+  def require_capability(cap)
+    # when the current token is nil, it means the user logged in with a different
+    # method, otherwise an OAuth token was used, which has to be checked.
+    unless current_token.nil?
+      unless current_token.read_attribute(cap)
+        render :text => "OAuth token doesn't have that capability.", :status => :forbidden
+        return false
+      end
+    end
+  end
+
+  # Utility methods to make the controller filter methods easier to read and write.
+  def require_allow_read_prefs
+    require_capability(:allow_read_prefs)
+  end
+  def require_allow_write_prefs
+    require_capability(:allow_write_prefs)
+  end
+  def require_allow_write_diary
+    require_capability(:allow_write_diary)
+  end
+  def require_allow_write_api
+    require_capability(:allow_write_api)
+  end
+  def require_allow_read_gpx
+    require_capability(:allow_read_gpx)
+  end
+  def require_allow_write_gpx
+    require_capability(:allow_write_gpx)
+  end
+
   ##
   # sets up the @user object for use by other methods. this is mostly called
   # from the authorize method, but can be called elsewhere if authorisation
   # is optional.
   def setup_user_auth
-    username, passwd = get_auth_data # parse from headers
-    # authenticate per-scheme
-    if username.nil?
-      @user = nil # no authentication provided - perhaps first connect (client should retry after 401)
-    elsif username == 'token' 
-      @user = User.authenticate(:token => passwd) # preferred - random token for user from db, passed in basic auth
+    # try and setup using OAuth
+    if oauthenticate
+      @user = current_token.user
     else
-      @user = User.authenticate(:username => username, :password => passwd) # basic auth
+      username, passwd = get_auth_data # parse from headers
+      # authenticate per-scheme
+      if username.nil?
+        @user = nil # no authentication provided - perhaps first connect (client should retry after 401)
+      elsif username == 'token'
+        @user = User.authenticate(:token => passwd) # preferred - random token for user from db, passed in basic auth
+      else
+        @user = User.authenticate(:username => username, :password => passwd) # basic auth
+      end
     end
   end
 
index e451f6d04904f80467620e16f612db6ac1cadc39..c67f4abd5e69c81a7ae68f860abbc5476f1a0193 100644 (file)
@@ -7,6 +7,7 @@ class ChangesetController < ApplicationController
   before_filter :authorize_web, :only => [:list, :list_user, :list_bbox]
   before_filter :set_locale, :only => [:list, :list_user, :list_bbox]
   before_filter :authorize, :only => [:create, :update, :delete, :upload, :include, :close]
+  before_filter :require_allow_write_api, :only => [:create, :update, :delete, :upload, :include, :close]
   before_filter :require_public_data, :only => [:create, :update, :delete, :upload, :include, :close]
   before_filter :check_api_writable, :only => [:create, :update, :delete, :upload, :include]
   before_filter :check_api_readable, :except => [:create, :update, :delete, :upload, :download, :query]
index eb6d0182326506d83d3e4c362560d362abd7921c..33e0ed3ee876f358c77c3e93dada13bd753ae716 100644 (file)
@@ -4,6 +4,7 @@ class NodeController < ApplicationController
   require 'xml/libxml'
 
   before_filter :authorize, :only => [:create, :update, :delete]
+  before_filter :require_allow_write_api, :only => [:create, :update, :delete]
   before_filter :require_public_data, :only => [:create, :update, :delete]
   before_filter :check_api_writable, :only => [:create, :update, :delete]
   before_filter :check_api_readable, :except => [:create, :update, :delete]
diff --git a/app/controllers/oauth_clients_controller.rb b/app/controllers/oauth_clients_controller.rb
new file mode 100644 (file)
index 0000000..00606c1
--- /dev/null
@@ -0,0 +1,53 @@
+class OauthClientsController < ApplicationController
+  layout 'site'
+
+  before_filter :authorize_web
+  before_filter :require_user
+  
+  def index
+    @client_applications = @user.client_applications
+    @tokens = @user.oauth_tokens.find :all, :conditions => 'oauth_tokens.invalidated_at is null and oauth_tokens.authorized_at is not null'
+  end
+
+  def new
+    @client_application = ClientApplication.new
+  end
+
+  def create
+    @client_application = @user.client_applications.build(params[:client_application])
+    if @client_application.save
+      flash[:notice] = "Registered the information successfully"
+      redirect_to :action => "show", :id => @client_application.id
+    else
+      render :action => "new"
+    end
+  end
+  
+  def show
+    @client_application = @user.client_applications.find(params[:id])
+  rescue ActiveRecord::RecordNotFound
+    @type = "client application"
+    render :action => "not_found", :status => :not_found
+  end
+
+  def edit
+    @client_application = @user.client_applications.find(params[:id])
+  end
+  
+  def update
+    @client_application = @user.client_applications.find(params[:id])
+    if @client_application.update_attributes(params[:client_application])
+      flash[:notice] = "Updated the client information successfully"
+      redirect_to :action => "show", :id => @client_application.id
+    else
+      render :action => "edit"
+    end
+  end
+
+  def destroy
+    @client_application = @user.client_applications.find(params[:id])
+    @client_application.destroy
+    flash[:notice] = "Destroyed the client application registration"
+    redirect_to :action => "index"
+  end
+end
diff --git a/app/controllers/oauth_controller.rb b/app/controllers/oauth_controller.rb
new file mode 100644 (file)
index 0000000..f8959be
--- /dev/null
@@ -0,0 +1,83 @@
+class OauthController < ApplicationController
+  layout 'site'
+
+  before_filter :authorize_web, :except => [:request_token, :access_token]
+  before_filter :require_user, :only => [:oauthorize]
+  before_filter :verify_oauth_consumer_signature, :only => [:request_token]
+  before_filter :verify_oauth_request_token, :only => [:access_token]
+  # Uncomment the following if you are using restful_open_id_authentication
+  # skip_before_filter :verify_authenticity_token
+
+  def request_token
+    @token = current_client_application.create_request_token
+
+    logger.info "in REQUEST TOKEN"
+    if @token
+      logger.info "request token params: #{params.inspect}"
+      # request tokens indicate what permissions the client *wants*, not
+      # necessarily the same as those which the user allows.
+      current_client_application.permissions.each do |pref|
+        logger.info "PARAMS found #{pref}"
+        @token.write_attribute(pref, true)
+      end
+      @token.save!
+
+      render :text => @token.to_query
+    else
+      render :nothing => true, :status => 401
+    end
+  end 
+  
+  def access_token
+    @token = current_token && current_token.exchange!
+    if @token
+      render :text => @token.to_query
+    else
+      render :nothing => true, :status => 401
+    end
+  end
+
+  def oauthorize
+    @token = RequestToken.find_by_token params[:oauth_token]
+    unless @token.invalidated?    
+      if request.post? 
+        any_auth = false
+        @token.client_application.permissions.each do |pref|
+          if params[pref]
+            logger.info "OAUTHORIZE PARAMS found #{pref}"
+            @token.write_attribute(pref, true)
+            any_auth ||= true
+          else
+            @token.write_attribute(pref, false)
+          end
+        end
+        
+        if any_auth
+          @token.authorize!(@user)
+          redirect_url = params[:oauth_callback] || @token.client_application.callback_url
+          if redirect_url
+            redirect_to "#{redirect_url}?oauth_token=#{@token.token}"
+          else
+            render :action => "authorize_success"
+          end
+        else
+          @token.invalidate!
+          render :action => "authorize_failure"
+        end
+      end
+    else
+      render :action => "authorize_failure"
+    end
+  end
+  
+  def revoke
+    @token = @user.oauth_tokens.find_by_token params[:token]
+    if @token
+      @token.invalidate!
+      flash[:notice] = "You've revoked the token for #{@token.client_application.name}"
+    end
+    logger.info "about to redirect"
+    redirect_to :controller => 'oauth_clients', :action => 'index'
+  end
+  
+end
index 4f8e2d0b52a344af8cda070bf6db60df938c51c8..390806f80a3268f8d53ce7f694aaa0c1de2ee046 100644 (file)
@@ -2,6 +2,7 @@ class RelationController < ApplicationController
   require 'xml/libxml'
 
   before_filter :authorize, :only => [:create, :update, :delete]
+  before_filter :require_allow_write_api, :only => [:create, :update, :delete]
   before_filter :require_public_data, :only => [:create, :update, :delete]
   before_filter :check_api_writable, :only => [:create, :update, :delete]
   before_filter :check_api_readable, :except => [:create, :update, :delete]
index d0e3a853c913cb42f0ff5c1ce81f909570b6ad5d..17b66796923f9e4021bb29a93733913e99f95fdc 100644 (file)
@@ -9,6 +9,8 @@ class TraceController < ApplicationController
   before_filter :check_database_writable, :only => [:create, :edit, :delete, :make_public]
   before_filter :check_api_readable, :only => [:api_details, :api_data]
   before_filter :check_api_writable, :only => [:api_create]
+  before_filter :require_allow_read_gpx, :only => [:api_details, :api_data]
+  before_filter :require_allow_write_gpx, :only => [:api_create]
  
   # Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
   #  target_user - if set, specifies the user to fetch traces for.  if not set will fetch all traces
index f4ff7fb7098bad18bf7dd28f293ffd4c7d6102ec..86b715154750dbd3d6203a846f4c471e2860b123 100644 (file)
@@ -8,6 +8,8 @@ class UserController < ApplicationController
   before_filter :check_database_readable, :except => [:api_details, :api_gpx_files]
   before_filter :check_database_writable, :only => [:login, :new, :set_home, :account, :go_public, :make_friend, :remove_friend, :upload_image, :delete_image]
   before_filter :check_api_readable, :only => [:api_details, :api_gpx_files]
+  before_filter :require_allow_read_prefs, :only => [:api_details]
+  before_filter :require_allow_read_gpx, :only => [:api_gpx_files]
 
   filter_parameter_logging :password, :pass_crypt, :pass_crypt_confirmation
 
@@ -37,6 +39,7 @@ class UserController < ApplicationController
 
   def account
     @title = t 'user.account.title'
+    @tokens = @user.oauth_tokens.find :all, :conditions => 'oauth_tokens.invalidated_at is null and oauth_tokens.authorized_at is not null'
 
     if params[:user] and params[:user][:display_name] and params[:user][:description]
       if params[:user][:email] != @user.email
index 59573047acc3591e22621f1fb041b99abe3f95d9..d02313497ef61408eb1667852c95abaa4e386366 100644 (file)
@@ -1,6 +1,8 @@
 # Update and read user preferences, which are arbitrayr key/val pairs
 class UserPreferenceController < ApplicationController
   before_filter :authorize
+  before_filter :require_allow_read_prefs, :only => [:read_one, :read]
+  before_filter :require_allow_write_prefs, :except => [:read_one, :read]
 
   def read_one
     pref = UserPreference.find(@user.id, params[:preference_key])
index 4d345e06382b99dd37db07bbf874c153a5100bbe..1f301e9fb168d805569d3d873ebb0c9a26d30a13 100644 (file)
@@ -2,6 +2,7 @@ class WayController < ApplicationController
   require 'xml/libxml'
 
   before_filter :authorize, :only => [:create, :update, :delete]
+  before_filter :require_allow_write_api, :only => [:create, :update, :delete]
   before_filter :require_public_data, :only => [:create, :update, :delete]
   before_filter :check_api_writable, :only => [:create, :update, :delete]
   before_filter :check_api_readable, :except => [:create, :update, :delete]
diff --git a/app/helpers/oauth_clients_helper.rb b/app/helpers/oauth_clients_helper.rb
new file mode 100644 (file)
index 0000000..3b909aa
--- /dev/null
@@ -0,0 +1,2 @@
+module OauthClientsHelper
+end
\ No newline at end of file
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
new file mode 100644 (file)
index 0000000..010cf9f
--- /dev/null
@@ -0,0 +1,2 @@
+module OauthHelper
+end
diff --git a/app/models/access_token.rb b/app/models/access_token.rb
new file mode 100644 (file)
index 0000000..b773310
--- /dev/null
@@ -0,0 +1,10 @@
+class AccessToken<OauthToken
+  validates_presence_of :user
+  before_create :set_authorized_at
+  
+protected 
+  
+  def set_authorized_at
+    self.authorized_at = Time.now
+  end
+end
\ No newline at end of file
diff --git a/app/models/client_application.rb b/app/models/client_application.rb
new file mode 100644 (file)
index 0000000..d3799ab
--- /dev/null
@@ -0,0 +1,59 @@
+require 'oauth'
+class ClientApplication < ActiveRecord::Base
+  belongs_to :user
+  has_many :tokens, :class_name => "OauthToken"
+  validates_presence_of :name, :url, :key, :secret
+  validates_uniqueness_of :key
+  before_validation_on_create :generate_keys
+  
+  def self.verify_request(request, options = {}, &block)
+    begin
+      signature = OAuth::Signature.build(request, options, &block)
+      logger.info "Signature Base String: #{signature.signature_base_string}"
+      logger.info "Consumer: #{signature.send :consumer_key}"
+      logger.info "Token: #{signature.send :token}"
+      return false unless OauthNonce.remember(signature.request.nonce, signature.request.timestamp)
+      value = signature.verify
+      logger.info "Signature verification returned: #{value.to_s}"
+      value
+    rescue OAuth::Signature::UnknownSignatureMethod => e
+      logger.info "ERROR"+e.to_s
+      false
+    end
+  end
+  
+  def self.all_permissions
+    PERMISSIONS
+  end
+
+  def oauth_server
+    @oauth_server ||= OAuth::Server.new("http://" + SERVER_URL)
+  end
+  
+  def credentials
+    @oauth_client ||= OAuth::Consumer.new(key, secret)
+  end
+    
+  def create_request_token
+    RequestToken.create :client_application => self
+  end
+
+  # the permissions that this client would like from the user
+  def permissions
+    ClientApplication.all_permissions.select { |p| self[p] }
+  end
+
+protected
+  
+  # this is the set of permissions that the client can ask for. clients
+  # have to say up-front what permissions they want and when users sign up they
+  # can agree or not agree to each of them.
+  PERMISSIONS = [:allow_read_prefs, :allow_write_prefs, :allow_write_diary,
+                 :allow_write_api, :allow_read_gpx, :allow_write_gpx ]
+
+  def generate_keys
+    @oauth_client = oauth_server.generate_consumer_credentials
+    self.key = @oauth_client.key
+    self.secret = @oauth_client.secret
+  end
+end
diff --git a/app/models/oauth_nonce.rb b/app/models/oauth_nonce.rb
new file mode 100644 (file)
index 0000000..075351b
--- /dev/null
@@ -0,0 +1,13 @@
+# Simple store of nonces. The OAuth Spec requires that any given pair of nonce and timestamps are unique.
+# Thus you can use the same nonce with a different timestamp and viceversa.
+class OauthNonce < ActiveRecord::Base
+  validates_presence_of :nonce, :timestamp
+  validates_uniqueness_of :nonce, :scope => :timestamp
+  
+  # Remembers a nonce and it's associated timestamp. It returns false if it has already been used
+  def self.remember(nonce, timestamp)
+    oauth_nonce = OauthNonce.create(:nonce => nonce, :timestamp => timestamp)
+    return false if oauth_nonce.new_record?
+    oauth_nonce
+  end
+end
diff --git a/app/models/oauth_token.rb b/app/models/oauth_token.rb
new file mode 100644 (file)
index 0000000..f64ec53
--- /dev/null
@@ -0,0 +1,41 @@
+class OauthToken < ActiveRecord::Base
+  belongs_to :client_application
+  belongs_to :user
+  validates_uniqueness_of :token
+  validates_presence_of :client_application, :token, :secret
+  before_validation_on_create :generate_keys
+  
+  def self.find_token(token_key)
+    token = OauthToken.find_by_token(token_key, :include => :client_application)
+    if token && token.authorized?
+      logger.info "Loaded #{token.token} which was authorized by (user_id=#{token.user_id}) on the #{token.authorized_at}"
+      token
+    else
+      nil
+    end
+  end
+  
+  def invalidated?
+    invalidated_at != nil
+  end
+  
+  def invalidate!
+    update_attribute(:invalidated_at, Time.now)
+  end
+  
+  def authorized?
+    authorized_at != nil && !invalidated?
+  end
+  
+  def to_query
+    "oauth_token=#{token}&oauth_token_secret=#{secret}"
+  end
+    
+protected
+  
+  def generate_keys
+    @oauth_token = client_application.oauth_server.generate_credentials
+    self.token = @oauth_token[0]
+    self.secret = @oauth_token[1]
+  end
+end
diff --git a/app/models/request_token.rb b/app/models/request_token.rb
new file mode 100644 (file)
index 0000000..d66fe6c
--- /dev/null
@@ -0,0 +1,23 @@
+class RequestToken < OauthToken
+  def authorize!(user)
+    return false if authorized?
+    self.user = user
+    self.authorized_at = Time.now
+    self.save
+  end
+  
+  def exchange!
+    return false unless authorized?
+    RequestToken.transaction do
+      params = { :user => user, :client_application => client_application }
+      # copy the permissions from the authorised request token to the access token
+      client_application.permissions.each { |p| 
+        params[p] = read_attribute(p)
+      }
+
+      access_token = AccessToken.create(params)
+      invalidate!
+      access_token
+    end
+  end
+end
index 9a1106972d63d767c2b2806f3eb5a921d4e1577e..1e594479728bde84bdad8ae237b368c9820762a2 100644 (file)
@@ -11,6 +11,9 @@ class User < ActiveRecord::Base
   has_many :preferences, :class_name => "UserPreference"
   has_many :changesets
 
+  has_many :client_applications
+  has_many :oauth_tokens, :class_name => "OauthToken", :order => "authorized_at desc", :include => [:client_application]
+
   validates_presence_of :email, :display_name
   validates_confirmation_of :email#, :message => ' addresses must match'
   validates_confirmation_of :pass_crypt#, :message => ' must match the confirmation password'
diff --git a/app/views/oauth/authorize_failure.html.erb b/app/views/oauth/authorize_failure.html.erb
new file mode 100644 (file)
index 0000000..d8110c9
--- /dev/null
@@ -0,0 +1 @@
+<h1>You have disallowed this request</h1>
diff --git a/app/views/oauth/authorize_success.html.erb b/app/views/oauth/authorize_success.html.erb
new file mode 100644 (file)
index 0000000..effe24a
--- /dev/null
@@ -0,0 +1 @@
+<h1>You have allowed this request</h1>
\ No newline at end of file
diff --git a/app/views/oauth/oauthorize.html.erb b/app/views/oauth/oauthorize.html.erb
new file mode 100644 (file)
index 0000000..0b9d321
--- /dev/null
@@ -0,0 +1,17 @@
+<h1>Authorize access to your account</h1>
+<p><%= t('oauth.client_application.request_access', :app_name => link_to(@token.client_application.name,@token.client_application.url)) %></p>
+<% form_tag authorize_url do %>
+  <%= hidden_field_tag "oauth_token", @token.token %>
+  <%- if params[:oauth_callback] -%>
+  <%= hidden_field_tag "oauth_callback", params[:oauth_callback] %>
+<%- end -%>
+<p><%= t 'oauth.client_application.allow_to' %></p>
+<ul style="list-style:none">
+<% @token.client_application.permissions.each do |perm| %>
+  <li><%= check_box_tag perm.to_s, "yes", @token.read_attribute(perm) %><%= t "oauth.client_application.#{perm}" %></li>
+<% end %>
+</ul>
+<p>
+       <%= submit_tag %>
+</p>
+<% end %>
diff --git a/app/views/oauth_clients/_form.html.erb b/app/views/oauth_clients/_form.html.erb
new file mode 100644 (file)
index 0000000..f8fd434
--- /dev/null
@@ -0,0 +1,23 @@
+<div class="field">
+       <label for="client_application_name"><%= t'oauth.client_application.form.name' %> (<%= t'oauth.client_application.form.required' %>)</label><br/>
+       <%= f.text_field :name %>
+</div>
+<div class="field">
+       <label for="client_application_url"><%= t'oauth.client_application.form.url' %> (<%= t'oauth.client_application.form.required' %>)</label><br/>
+       <%= f.text_field :url %>
+</div>
+<div class="field">
+       <label for="client_application_callback_url"><%= t'oauth.client_application.form.callback_url' %></label><br/>
+       <%= f.text_field :callback_url %>
+</div>
+<div class="field">
+       <label for="client_application_support_url"><%= t'oauth.client_application.form.support_url' %></label><br/>
+       <%= f.text_field :support_url %>
+</div>
+<p><%= t'oauth.client_application.form.requests' %></p>
+<% ClientApplication.all_permissions.each do |perm| %>
+<div class="field">
+  <%= f.check_box perm %>
+  <label for="client_application_<%= perm.to_s %>"><%= t('oauth.client_application.form.' + perm.to_s) %></label><br/>
+</div>
+<% end %>
diff --git a/app/views/oauth_clients/edit.html.erb b/app/views/oauth_clients/edit.html.erb
new file mode 100644 (file)
index 0000000..855fc03
--- /dev/null
@@ -0,0 +1,6 @@
+<h1><%= t'oauth.client_application.edit.title' %></h1>
+<% form_for :client_application, @client_application, :url => oauth_client_path(@client_application.user.display_name, @client_application), :html => { :method => :put } do |f| %>
+       <%= render :partial => "form", :locals => { :f => f } %>
+       <br/>
+       <%= submit_tag t'oauth.client_application.edit.submit' %>
+<% end %>
diff --git a/app/views/oauth_clients/index.html.erb b/app/views/oauth_clients/index.html.erb
new file mode 100644 (file)
index 0000000..9f11cdd
--- /dev/null
@@ -0,0 +1,33 @@
+<h1><%= t'oauth.client_application.index.title' %></h1>
+<% unless @tokens.empty? %>
+<h3><%= t'oauth.client_application.index.my_tokens' %></h3>
+<p><%= t'oauth.client_application.index.list_tokens' %></p>
+<table>
+  <tr><th><%= t'oauth.client_application.index.application' %></th>
+    <th><%= t'oauth.client_application.index.issued_at' %></th><th>&nbsp;</th></tr>
+  <% @tokens.each do |token|%>
+    <% content_tag_for :tr, token do %>
+      <td><%= link_to token.client_application.name, token.client_application.url %></td>
+      <td><%= token.authorized_at %></td>
+      <td>
+       <% form_tag :controller => 'oauth', :action => 'revoke' do %>
+       <%= hidden_field_tag 'token', token.token %>
+       <%= submit_tag t('oauth.client_application.index.revoke') %>
+       <% end %>
+      </td>
+    <% end %>
+  <% end %>    
+</table>
+<% end %>
+<h3><%= t'oauth.client_application.index.my_apps' %></h3>
+<% if @client_applications.empty? %>
+<p><%= t('oauth.client_application.index.no_apps', :oauth => "<a href=\"http://oauth.net\">OAuth</a>") %></p>
+<% else %>
+<p><%= t'oauth.client_application.index.registered_apps' %></p>
+<% @client_applications.each do |client|%>
+  <% div_for client do %>
+    <%= link_to client.name, :action => :show, :id => client.id %>
+  <% end %>
+<% end %>
+<% end %>
+<h3><%= link_to t('oauth.client_application.index.register_new'), :action => :new %></h3>
diff --git a/app/views/oauth_clients/new.html.erb b/app/views/oauth_clients/new.html.erb
new file mode 100644 (file)
index 0000000..75102f8
--- /dev/null
@@ -0,0 +1,6 @@
+<h1><%= t'oauth.client_application.new.title' %></h1>
+<% form_for :client_application, :url => { :action => :create } do |f| %>
+   <%= render :partial => "form", :locals => { :f => f } %>
+   <br />
+   <%= submit_tag t'oauth.client_application.new.submit' %>
+<% end %>
diff --git a/app/views/oauth_clients/not_found.erb b/app/views/oauth_clients/not_found.erb
new file mode 100644 (file)
index 0000000..9a9865b
--- /dev/null
@@ -0,0 +1 @@
+<p><%= t('oauth.client_application.not_found', :type => @type) %></p>
diff --git a/app/views/oauth_clients/show.html.erb b/app/views/oauth_clients/show.html.erb
new file mode 100644 (file)
index 0000000..df8fbc2
--- /dev/null
@@ -0,0 +1,28 @@
+<h1><%= t('oauth.client_application.show.title', :app_name => @client_application.name) %></h1>
+<p>
+       <b><%= t'oauth.client_application.show.key' %></b> <%=@client_application.key %>
+</p>
+<p>
+       <b><%= t'oauth.client_application.show.secret' %></b> <%=@client_application.secret %>
+</p>
+<p>
+       <b><%= t'oauth.client_application.show.url' %></b> http<%='s' if request.ssl? %>://<%= request.host_with_port %><%=@client_application.oauth_server.request_token_path %>
+</p>
+<p>
+       <b><%= t'oauth.client_application.show.access_url' %></b> http<%='s' if request.ssl? %>://<%= request.host_with_port %><%=@client_application.oauth_server.access_token_path %>
+</p>
+<p>
+       <b><%= t'oauth.client_application.show.authorize_url' %></b> http<%='s' if request.ssl? %>://<%= request.host_with_port %><%=@client_application.oauth_server.authorize_path %>
+</p>
+
+<p><%= t'oauth.client_application.show.requests' %></p>
+<ul><% @client_application.permissions.each do |perm| %>
+<div class="field">
+  <li><%= t('oauth.client_application.form.' + perm.to_s) %></li>
+</div>
+<% end %></ul>
+
+<p><%= t'oauth.client_application.show.support_notice' %></p>
+
+<p><%= link_to t('oauth.client_application.show.edit'), edit_oauth_client_url(@client_application.user.display_name, @client_application) %></p>
+
index 15a8f6827054cd2d50a4cbf371a578ac10264c26..45a129077563145ca47ed20e7c2542be4f54b0a9 100644 (file)
@@ -29,7 +29,7 @@
   <div id="map" style="border:1px solid black; position:relative; width:500px; height:400px;"></div>
   </td></tr>
   
-  <tr><td></td><td align=right><br/></br><%= submit_tag t('user.account.save changes button') %></td></tr>
+  <tr><td></td><td align=right><br/><%= submit_tag t('user.account.save changes button') %></td></tr>
 </table>
 <br/>
 
index ff349858c9229fd42916982fd0786c5fed3207f1..931037319a2d909d21815efa7cb6820778a64621 100644 (file)
 <br/>
 <% if @user and @this_user.id == @user.id %>
 <%= link_to t('user.view.change your settings'), :controller => 'user', :action => 'account', :display_name => @user.display_name %>
+<br/><br/>
+<%= link_to t('user.view.my_oauth_details'), :controller => 'oauth_clients', :action => 'index' %>
 <% end %>
index c7fa3c483ea0ca64964edd71d03c09f12024232f..e35353c3cd6b851ebecad7515d8000fd6a0f1f27 100644 (file)
@@ -49,6 +49,9 @@ Rails::Initializer.run do |config|
   config.gem 'composite_primary_keys', :version => '2.2.2'
   config.gem 'libxml-ruby', :version => '>= 1.1.1', :lib => 'libxml'
   config.gem 'rmagick', :lib => 'RMagick'
+  # note: this should be changed to 0.3.6 as soon as it's released, as this has fixes for
+  # uploading multipart documents.
+  config.gem 'oauth', :version => '>=0.2.1'
 
   # Only load the plugins named here, in the order given. By default, all plugins 
   # in vendor/plugins are loaded in alphabetical order.
index 37b099b954f69c2c26d51a52335ee60732ec4d1d..797a7328fbb0aa0d30a1bdc7c007e24e677367cc 100644 (file)
@@ -775,6 +775,21 @@ de:
       scheduled_for_deletion: "Für Löschung vorgesehener Track" 
     make_public: 
       made_public: "veröffentlichter Track"
+  oauth:
+    client_application:
+      request_access: "Die Anwendung {{app_name}} möchte auf Deinen OpenStreetMap-Account zugreifen. Bitte entscheide, ob Du der Anwendung die folgenden Rechte gewähren möchtest. Du kannst alle oder einige der folgenden Rechte gewähren:"
+      allow_to: "Erlaube der Anwendung:"
+      allow_read_prefs:  "Deine Benutzereinstellungen zu lesen"
+      allow_write_prefs: "Deine Benutzereinstellungen zu verändern"
+      allow_write_diary: "Blog-Einträge und Kommentare zu schreiben und Freunde einzutragen"
+      allow_write_api:   "Die OSM-Datenbank zu ändern"
+      allow_read_gpx:    "Deine privaten GPS-Tracks auszulesen"
+      allow_write_gpx:   "GPS-Tracks hochzuladen"
+    token:
+      none: "Du hast bislang keinen Anwendungen Zugriff auf Deinen Account gewährt. Du musst jetzt nichts unternehmen, denn die Anwendungen werden Dich dazu auffordern, wenn es nötig ist. Zu einem späteren Zeitpunkt kannst Du in diesem Menü sehen, welche Anwendungen Zugriff erhalten haben, und kannst diese Erlaubnis hier auch widerrufen."
+      application: "Anwendung"
+      issued: "Zugriff gewährt"
+      revoke: "widerrufen"
   user:
     login:
       title: "Anmelden"
index ad857b8755e998d422c4c76f9dfee2e32ae989c1..2cf7a3aa8f72e79ee6f07d703d6b7008d0e3d411 100644 (file)
@@ -775,6 +775,63 @@ en:
       scheduled_for_deletion: "Track scheduled for deletion"
     make_public:
       made_public: "Track made public"
+  oauth:
+    client_application:
+      request_access: "The application {{app_name}} is requesting access to your account. Please check whether you would like the application to have the following capabilities. You may choose as many or as few as you like."
+      allow_to: "Allow the client application to:"
+      allow_read_prefs:  "read your user preferences."
+      allow_write_prefs: "modify your user preferences."
+      allow_write_diary: "create diary entries, comments and make friends."
+      allow_write_api:   "modify the map."
+      allow_read_gpx:    "read your private GPS traces."
+      allow_write_gpx:   "upload GPS traces."
+      new:
+        title: "Register a new application"
+        submit: "Register"
+      edit:
+        title: "Edit your application"
+        submit: "Edit"
+      show:
+        title: "OAuth details for {{app_name}}"
+        key: "Consumer Key:"
+        secret: "Consumer Secret:"
+        url: "Request Token URL:"
+        access_url: "Access Token URL:"
+        authorize_url: "Authorise URL:"
+        support_notice: "We support hmac-sha1 (recommended) as well as plain text in ssl mode."
+        edit: "Edit Details"
+        requests: "Requesting the following permissions from the user:"
+        allow_read_prefs:  "read their user preferences."
+        allow_write_prefs: "modify their user preferences."
+        allow_write_diary: "create diary entries, comments and make friends."
+        allow_write_api:   "modify the map."
+        allow_read_gpx:    "read their private GPS traces."
+        allow_write_gpx:   "upload GPS traces."
+      index:
+        title: "My OAuth Details"
+        my_tokens: "My Authorised Applications"
+        list_tokens: "The following tokens have been issued to applications in your name:"
+        application: "Application Name"
+        issued_at: "Issued At"
+        revoke: "Revoke!"
+        my_apps: "My Client Applications"
+        no_apps: "Do you have an application you would like to register for use with us using the {{oauth}} standard? You must register your web application before it can make OAuth requests to this service."
+        registered_apps: "You have the following client applications registered:"
+        register_new: "Register your application"
+      form:
+        name: "Name"
+        required: "Required"
+        url: "Main Application URL"
+        callback_url: "Callback URL"
+        support_url: "Support URL"
+        requests: "Request the following permissions from the user:"
+        allow_read_prefs:  "read their user preferences."
+        allow_write_prefs: "modify their user preferences."
+        allow_write_diary: "create diary entries, comments and make friends."
+        allow_write_api:   "modify the map."
+        allow_read_gpx:    "read their private GPS traces."
+        allow_write_gpx:   "upload GPS traces."
+      not_found: "Sorry, that {{type}} could not be found."
   user:
     login:
       title: "Login"
@@ -851,6 +908,7 @@ en:
       nearby users: "Nearby users: "
       no nearby users: "There are no users who admit to mapping nearby yet."
       change your settings: change your settings
+      my_oauth_details: "View my OAuth details"
     friend_map:
       your location: Your location
       nearby mapper: "Nearby mapper: "
index 5ac2d744a77e73f7f7abbf8b4ac7fc63b795b735..0bc0d8cd390f17c2bc222730fbfd11f4fc67fcdc 100644 (file)
@@ -187,7 +187,6 @@ ActionController::Routing::Routes.draw do |map|
   map.connect '/export/finish', :controller => 'export', :action => 'finish'
 
   # messages
-
   map.connect '/user/:display_name/inbox', :controller => 'message', :action => 'inbox'
   map.connect '/user/:display_name/outbox', :controller => 'message', :action => 'outbox'
   map.connect '/message/new/:display_name', :controller => 'message', :action => 'new'
@@ -196,6 +195,14 @@ ActionController::Routing::Routes.draw do |map|
   map.connect '/message/reply/:message_id', :controller => 'message', :action => 'reply'
   map.connect '/message/delete/:message_id', :controller => 'message', :action => 'delete'
 
+  # oauth admin pages (i.e: for setting up new clients, etc...)
+  map.resources :oauth_clients, :path_prefix => '/user/:display_name'
+  map.connect '/oauth/revoke', :controller => 'oauth', :action => 'revoke'
+  map.authorize '/oauth/authorize', :controller => 'oauth', :action => 'oauthorize'
+  map.request_token '/oauth/request_token', :controller => 'oauth', :action => 'request_token'
+  map.access_token '/oauth/access_token', :controller => 'oauth', :action => 'access_token'
+  map.test_request '/oauth/test_request', :controller => 'oauth', :action => 'test_request'
+
   # fall through
   map.connect ':controller/:id/:action'
   map.connect ':controller/:action'
diff --git a/db/migrate/039_create_oauth_tables.rb b/db/migrate/039_create_oauth_tables.rb
new file mode 100644 (file)
index 0000000..95d6905
--- /dev/null
@@ -0,0 +1,44 @@
+class CreateOauthTables < ActiveRecord::Migration
+  def self.up
+    create_table :client_applications do |t|
+      t.string :name
+      t.string :url
+      t.string :support_url
+      t.string :callback_url
+      t.string :key, :limit => 50
+      t.string :secret, :limit => 50
+      t.integer :user_id
+
+      t.timestamps
+    end
+    add_index :client_applications, :key, :unique => true
+    
+    create_table :oauth_tokens do |t|
+      t.integer :user_id
+      t.string :type, :limit => 20
+      t.integer :client_application_id
+      t.string :token, :limit => 50
+      t.string :secret, :limit => 50
+      t.timestamp :authorized_at, :invalidated_at
+      t.timestamps
+    end
+    
+    add_index :oauth_tokens, :token, :unique => true
+    
+    create_table :oauth_nonces do |t|
+      t.string :nonce
+      t.integer :timestamp
+
+      t.timestamps
+    end
+    add_index :oauth_nonces, [:nonce, :timestamp], :unique => true
+    
+  end
+
+  def self.down
+    drop_table :client_applications
+    drop_table :oauth_tokens
+    drop_table :oauth_nonces
+  end
+
+end
diff --git a/db/migrate/040_add_fine_o_auth_permissions.rb b/db/migrate/040_add_fine_o_auth_permissions.rb
new file mode 100644 (file)
index 0000000..ad4c7a8
--- /dev/null
@@ -0,0 +1,23 @@
+class AddFineOAuthPermissions < ActiveRecord::Migration
+  PERMISSIONS = [:allow_read_prefs, :allow_write_prefs, :allow_write_diary,
+                 :allow_write_api, :allow_read_gpx, :allow_write_gpx ]
+
+  def self.up
+    PERMISSIONS.each do |perm|
+      # add fine-grained permissions columns for OAuth tokens, allowing people to
+      # give permissions to parts of the site only.
+      add_column :oauth_tokens, perm, :boolean, :null => false, :default => false
+
+      # add fine-grained permissions columns for client applications, allowing the
+      # client applications to request particular privileges.
+      add_column :client_applications, perm, :boolean, :null => false, :default => false
+    end
+  end
+
+  def self.down
+    PERMISSIONS.each do |perm|
+      remove_column :oauth_tokens, perm
+      remove_column :client_applications, perm
+    end
+  end
+end
diff --git a/db/migrate/041_add_foreign_keys_to_oauth_tables.rb b/db/migrate/041_add_foreign_keys_to_oauth_tables.rb
new file mode 100644 (file)
index 0000000..09de543
--- /dev/null
@@ -0,0 +1,15 @@
+require 'lib/migrate'
+
+class AddForeignKeysToOauthTables < ActiveRecord::Migration
+  def self.up
+    add_foreign_key :oauth_tokens, [:user_id], :users, [:id]
+    add_foreign_key :oauth_tokens, [:client_application_id], :client_applications, [:id]
+    add_foreign_key :client_applications, [:user_id], :users, [:id]
+  end
+
+  def self.down
+    remove_foreign_key :oauth_tokens, [:user_id], :users
+    remove_foreign_key :oauth_tokens, [:client_application_id], :client_applications
+    remove_foreign_key :client_applications, [:user_id], :users
+  end
+end
diff --git a/test/fixtures/client_applications.yml b/test/fixtures/client_applications.yml
new file mode 100644 (file)
index 0000000..9fe0889
--- /dev/null
@@ -0,0 +1,12 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+oauth_web_app:
+  name: Some OAuth Web App
+  created_at: "2009-04-21 00:00:00"
+  support_url: http://some.web.app.org/support
+  updated_at: "2009-04-21 00:00:00"
+  callback_url: http://some.web.app.org/callback
+  url: http://some.web.app.org/
+  user_id: 2
+  secret: Ur1s9LWWJJuYBiV9cDi3za3OV8TGCoRgUvVXJ5zp7pc
+  key: ewvENqsaTXFnZbMWmGDX2g
diff --git a/test/integration/client_application_test.rb b/test/integration/client_application_test.rb
new file mode 100644 (file)
index 0000000..d4fd68a
--- /dev/null
@@ -0,0 +1,81 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ClientApplicationTest < ActionController::IntegrationTest
+  fixtures :users, :client_applications
+
+  ##
+  # run through the procedure of creating a client application and checking
+  # that it shows up on the user's account page.
+  def test_create_application
+    post '/login', {'user[email]' => "test@example.com", 'user[password]' => "test", :referer => '/user/test2'}
+    assert_response :redirect
+    follow_redirect!
+    assert_response :success
+    assert_template 'user/view'
+
+    # check that the form to allow new client application creations exists
+    assert_in_body do
+      assert_select "a[href='/user/test2/oauth_clients']"
+    end
+
+    # now we follow the link to the oauth client list
+    get '/user/test2/oauth_clients'
+    assert_response :success
+    assert_in_body do
+      assert_select "a[href='/user/test2/oauth_clients/new']"
+    end
+
+    # now we follow the link to the new oauth client page
+    get '/user/test2/oauth_clients/new'
+    assert_response :success
+    assert_in_body do
+      assert_select "h1", "Register a new application"
+      assert_select "form[action='/user/test2/oauth_clients']" do
+        [ :name, :url, :callback_url, :support_url ].each do |inp|
+          assert_select "input[name=?]", "client_application[#{inp}]"
+        end
+        ClientApplication.all_permissions.each do |perm|
+          assert_select "input[name=?]", "client_application[#{perm}]"
+        end
+      end
+    end
+
+    post '/user/test2/oauth_clients', {
+      'client_application[name]' => 'My New App',
+      'client_application[url]' => 'http://my.new.app.org/',
+      'client_application[callback_url]' => 'http://my.new.app.org/callback',
+      'client_application[support_url]' => 'http://my.new.app.org/support'}
+    assert_response :redirect
+    follow_redirect!
+    assert_response :success
+    assert_template 'oauth_clients/show'
+    assert_equal 'Registered the information successfully', flash[:notice]
+
+    # now go back to the account page and check its listed under this user
+    get '/user/test2/oauth_clients'
+    assert_response :success
+    assert_template 'oauth_clients/index'
+    assert_in_body { assert_select "div>a", "My New App" }
+  end
+
+  ##
+  # fake client workflow.
+  # this acts like a 3rd party client trying to access the site.
+  def test_3rd_party_token
+    # apparently the oauth gem doesn't really support being used inside integration
+    # tests, as its too tied into the HTTP headers and stuff that it signs.
+  end
+
+  ##
+  # utility method to make the HTML screening easier to read.
+  def assert_in_body
+    assert_select "html:root" do
+      assert_select "body" do
+        assert_select "div#content" do
+          yield
+        end
+      end
+    end
+  end
+
+end
index 97c74900075def22db5e50c94a17d818b8b42334..4972ee6d6e6b90b1d7fb14c8f2e54ed687fdf9e0 100644 (file)
@@ -71,6 +71,8 @@ class ActiveSupport::TestCase
     set_fixture_class :gpx_files => 'Trace'
     set_fixture_class :gps_points => 'Tracepoint'
     set_fixture_class :gpx_file_tags => 'Tracetag'
+
+    fixtures :client_applications
   end
 
   ##
diff --git a/test/unit/oauth_nonce_test.rb b/test/unit/oauth_nonce_test.rb
new file mode 100644 (file)
index 0000000..def869a
--- /dev/null
@@ -0,0 +1,20 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class OauthNonceTest < ActiveSupport::TestCase
+  api_fixtures
+
+  ##
+  # the nonce has only one property, that it is a unique pair of
+  # string and timestamp.
+  def test_nonce_uniqueness
+    string = "0123456789ABCDEF"
+    timestamp = Time.now
+    
+    nonce1 = OauthNonce.remember(string, timestamp)
+    assert_not_equal false, nonce1, "First nonce should be unique. Check your test database is empty."
+
+    nonce2 = OauthNonce.remember(string, timestamp)
+    assert_equal false, nonce2, "Shouldn't be able to remember the same nonce twice."
+  end
+
+end
diff --git a/test/unit/oauth_token_test.rb b/test/unit/oauth_token_test.rb
new file mode 100644 (file)
index 0000000..655e64e
--- /dev/null
@@ -0,0 +1,37 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class OauthTokenTest < ActiveSupport::TestCase
+  api_fixtures
+
+  ##
+  # check that after calling invalidate! on a token, it is invalid.
+  def test_token_invalidation
+    tok = OauthToken.new
+    assert_equal false, tok.invalidated?, "Token should be created valid."
+    tok.invalidate!
+    assert_equal true, tok.invalidated?, "Token should now be invalid."
+  end
+
+  ##
+  # check that an authorized token is authorised and can be invalidated
+  def test_token_authorisation
+    tok = RequestToken.create :client_application => client_applications(:oauth_web_app)
+    assert_equal false, tok.authorized?, "Token should be created unauthorised."
+    tok.authorize!(users(:public_user))
+    assert_equal true, tok.authorized?, "Token should now be authorised."
+    tok.invalidate!
+    assert_equal false, tok.authorized?, "Token should now be invalid."
+  end
+
+  ##
+  # test that tokens can't be found unless they're authorised
+  def test_find_token
+    tok = client_applications(:oauth_web_app).create_request_token
+    assert_equal false, tok.authorized?, "Token should be created unauthorised."
+    assert_equal nil, OauthToken.find_token(tok.token), "Shouldn't be able to find unauthorised token"
+    tok.authorize!(users(:public_user))
+    assert_equal true, tok.authorized?, "Token should now be authorised."
+    assert_not_equal nil, OauthToken.find_token(tok.token), "Should be able to find authorised token"
+  end
+
+end
diff --git a/vendor/plugins/oauth-plugin/.gitignore b/vendor/plugins/oauth-plugin/.gitignore
new file mode 100644 (file)
index 0000000..56cb2dc
--- /dev/null
@@ -0,0 +1,5 @@
+doc
+pkg
+*.log
+.DS_Store
+.svn
diff --git a/vendor/plugins/oauth-plugin/CHANGELOG b/vendor/plugins/oauth-plugin/CHANGELOG
new file mode 100644 (file)
index 0000000..a4006aa
--- /dev/null
@@ -0,0 +1,61 @@
+2/11/2009
+- Fixed escaping error and file path error in the generator simultaneously reported and fixed by Ivan Valdes and Mike Demers thanks
+
+2/9/2009
+- Fixed compatibility issue with OAuth Gem 3.1 (wr0ngway and aeden)
+- Added Test:Unit tests to generator (Ed Hickey)
+- added missing oauth_clients/edit.html.erb view template (Ed Hickey)
+- added missing :oauth_clients resource route in USAGE (Ed Hickey)
+- Don't throw NPE it token is not in db (Haruska)
+- Cleaned up whitespace (bricolage, Nicholas Nam)
+- Fixed bug in default verify_oauth_signature (igrigorik)
+- Doc fixes (skippy)
+
+6/23/2008
+
+- Split OAuth controller into two parts: OAuth and OAuth clients. [jcrosby]
+
+revision 31
+
+- patch that fixes a problem in oauth_required from Hannes Tyden and Sean Treadway from SoundCloud. Thanks.
+
+revision 30
+
+- updated to use oauth gem 0.2.1
+
+
+revision 23
+
+- removed all core libraries from plugin. They are now in the oauth gem.
+
+# oauth-plugin-pre-gem Branch created
+
+revision 18
+- added a generator for creation oauth_providers
+
+revision 12
+- the bug with post and put has now been fixed.
+- better documentation
+
+revision 9
+- added a test helper. Include OAuth::TestHelper in your tests or specs to mock incoming requests
+
+revision: 8
+- moved tests into oauth folder and renamed them to make them work with autotest by default
+- Refactored the request methods to make them more flexible and ready for integrating with ActiveResource
+- There are a few tests that fail. All of them to do with put and post requests with payload data. I decided to commit anyway, to get the new api out.
+
+revision: 7
+
+- Done a lot of work on the Server side of things. The Server class has changed a lot and is likely to be incompatible with previous versions
+
+revision: 6
+
+- Throws InsecureSignatureMethod exception if attempting to use straight sha1 or md5.
+- Disables plaintext signature over http (throws an InsecureSignatureMethod)
+- Better testing of signature methods - the prior tests were seriously flawed.
+
+revision: 5
+
+- Removed support for sha1 and md5
+- Implemented draft 6 support of OAuth removing secrets from base string
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/MIT-LICENSE b/vendor/plugins/oauth-plugin/MIT-LICENSE
new file mode 100644 (file)
index 0000000..570ecf8
--- /dev/null
@@ -0,0 +1,20 @@
+Copyright (c) 2007 [name of plugin creator]
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/oauth-plugin/README.rdoc b/vendor/plugins/oauth-plugin/README.rdoc
new file mode 100644 (file)
index 0000000..e2e68b7
--- /dev/null
@@ -0,0 +1,110 @@
+= OAuth Plugin
+
+This is the beginning of a plugin for implementing OAuth Providers in Rails applications.
+
+See the OAuth specs at:
+
+http://oauth.net/core/1.0/
+
+and the OAuth site at:
+
+http://oauth.net
+
+== Requirements
+
+You need to install the oauth gem (0.2.1) which is the core OAuth ruby library. It will NOT work on any previous version of the gem.
+  
+  sudo gem install oauth
+
+The Generator currently creates code (in particular views) that only work in Rails 2.
+
+It should not be difficult to manually modify the code to work on Rails 1.2.x
+
+I think the only real issue is that the views have .html.erb extensions. So these could theoretically just be renamed to .rhtml.
+
+Please let me know if this works and I will see if I can make the generator conditionally create .rhtml for pre 2.0 versions of RAILS.
+
+== OAuth Provider generator
+
+While it isn't very flexible at the moment there is an oauth_provider generator which you can use like this:
+
+./script/generate oauth_provider
+
+This generates OAuth and OAuth client controllers as well as the required models.
+
+It requires an authentication framework such as acts_as_authenticated, restful_authentication or restful_open_id_authentication. It also requires Rails 2.0.
+
+=== Routes
+
+You need to add the following to your routes (config/routes.rb)
+
+       map.resources :oauth_clients
+       map.authorize '/oauth/authorize',:controller=>'oauth',:action=>'authorize'
+       map.request_token '/oauth/request_token',:controller=>'oauth',:action=>'request_token'
+       map.access_token '/oauth/access_token',:controller=>'oauth',:action=>'access_token'
+       map.test_request '/oauth/test_request',:controller=>'oauth',:action=>'test_request'
+
+=== User Model
+
+Add the following lines to your user model:
+
+  has_many :client_applications
+  has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application]
+
+=== Migrate database
+
+The database is defined in:
+       
+       db/migrate/XXX_create_oauth_tables.rb
+
+Run them as any other normal migration in rails with:
+
+  rake db:migrate
+
+=== RSpec
+
+The generator installs a collection of RSpec (http://rspec.info) specs instead of normal unit_tests. If you don't use RSpec (and really why aren't you?) feel free to remove the spec folder.
+       
+If you would like to contribute regular unit tests I will accept them with a smile.
+
+== Protecting your actions
+
+I recommend that you think about what your users would want to provide access to and limit oauth for those only. For example in a CRUD controller you may think about if you want to let consumer applications do the create, update or delete actions. For your application this might make sense, but for others maybe not.
+
+If you want to give oauth access to everything a registered user can do, just replace the filter you have in your controllers with:
+
+       before_filter :login_or_oauth_required
+       
+If you want to restrict consumers to the index and show methods of your controller do the following:
+
+       before_filter :login_required,:except=>[:show,:index]
+       before_filter :login_or_oauth_required,:only=>[:show,:index]
+
+If you have an action you only want used via oauth:
+
+       before_filter :oauth_required
+
+All of these places the tokens user in current_user as you would expect. It also exposes the following methods:
+
+* current_token - for accessing the token used to authorize the current request
+* current_client_application - for accessing information about which consumer is currently accessing your request
+
+You could add application specific information to the OauthToken and ClientApplication model for such things as object level access control, billing, expiry etc. Be creative and you can create some really cool applications here.
+
+== More
+
+The Google Code project is http://code.google.com/p/oauth-plugin/
+
+The Mailing List for all things OAuth in Ruby is:
+
+http://groups.google.com/group/oauth-ruby
+
+The Mailing list for everything else OAuth is:
+
+http://groups.google.com/group/oauth
+
+The OAuth Ruby Gem home page is http://oauth.rubyforge.org
+
+Please help documentation, patches and testing.
+
+Copyright (c) 2007-2008 Pelle Braendgaard, released under the MIT license
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/Rakefile b/vendor/plugins/oauth-plugin/Rakefile
new file mode 100644 (file)
index 0000000..16a9769
--- /dev/null
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the oauth plugin.'
+Rake::TestTask.new(:test) do |t|
+  t.libs << 'lib'
+  t.pattern = 'test/**/*_test.rb'
+  t.verbose = true
+end
+
+desc 'Generate documentation for the oauth plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+  rdoc.rdoc_dir = 'rdoc'
+  rdoc.title    = 'Oauth'
+  rdoc.options << '--line-numbers' << '--inline-source'
+  rdoc.rdoc_files.include('README')
+  rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/USAGE b/vendor/plugins/oauth-plugin/generators/oauth_provider/USAGE
new file mode 100644 (file)
index 0000000..ded11ac
--- /dev/null
@@ -0,0 +1,24 @@
+./script/generate oauth_provider 
+
+This creates an OAuth Provider controller as well as the requisite models.
+
+It requires an authentication framework such as acts_as_authenticated, restful_authentication or restful_open_id_authentication.
+
+If you generated the migration file (true by default), make sure you run
+rake db:migrate
+
+You need to add the following routes to your config/routes.rb file:
+
+map.resources :oauth_clients
+map.oauth '/oauth',:controller=>'oauth',:action=>'index'
+map.authorize '/oauth/authorize',:controller=>'oauth',:action=>'authorize'
+map.request_token '/oauth/request_token',:controller=>'oauth',:action=>'request_token'
+map.access_token '/oauth/access_token',:controller=>'oauth',:action=>'access_token'
+map.test_request '/oauth/test_request',:controller=>'oauth',:action=>'test_request'
+
+include the following in your user.rb
+
+has_many :client_applications
+has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application]
+
+
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/oauth_provider_generator.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/oauth_provider_generator.rb
new file mode 100644 (file)
index 0000000..57059e2
--- /dev/null
@@ -0,0 +1,116 @@
+class OauthProviderGenerator < Rails::Generator::Base
+  default_options :skip_migration => false
+  attr_reader   :class_path,
+                :controller_name,
+                :controller_class_path,
+                :controller_file_path,
+                :controller_class_name,
+                :controller_singular_name,
+                :controller_plural_name
+  alias_method  :controller_file_name,  :controller_singular_name
+
+  def initialize(runtime_args, runtime_options = {})
+    super
+
+    @controller_name = args.shift || 'oauth'
+    @controller_singular_name = 'oauth'
+    @controller_plural_name = 'oauth'
+    @controller_file_name = 'oauth'
+    @controller_class_name="Oauth"
+    @class_path=''
+    @controller_class_path=''
+  end
+
+  def manifest
+    record do |m|
+      
+      # Check for class naming collisions.
+      # Check for class naming collisions.
+      m.class_collisions controller_class_path,       "#{controller_class_name}Controller", # Oauth Controller
+                                                      "#{controller_class_name}Helper",
+                                                      "#{controller_class_name}ClientsController",
+                                                      "#{controller_class_name}ClientsHelper"
+      m.class_collisions class_path,                  "ClientApplication","OauthNonce","RequestToken","AccessToken","OauthToken"
+
+      # Controller, helper, views, and test directories.
+      m.directory File.join('app/models', class_path)
+      m.directory File.join('app/controllers', controller_class_path)
+      m.directory File.join('app/helpers', controller_class_path)
+      m.directory File.join('app/views', controller_class_path, controller_file_name)
+      m.directory File.join('app/views', controller_class_path, 'oauth_clients')
+
+      m.template 'client_application.rb',File.join('app/models',"client_application.rb")
+      m.template 'oauth_token.rb',    File.join('app/models',"oauth_token.rb")
+      m.template 'request_token.rb',  File.join('app/models',"request_token.rb")
+      m.template 'access_token.rb',   File.join('app/models',"access_token.rb")
+      m.template 'oauth_nonce.rb',    File.join('app/models',"oauth_nonce.rb")
+
+      m.template 'controller.rb',File.join('app/controllers',controller_class_path,"#{controller_file_name}_controller.rb")
+      m.template 'helper.rb',File.join('app/helpers',controller_class_path,"#{controller_file_name}_helper.rb")
+
+      m.template 'clients_controller.rb',File.join('app/controllers',controller_class_path,"#{controller_file_name}_clients_controller.rb")
+      m.template 'clients_helper.rb',File.join('app/helpers',controller_class_path,"#{controller_file_name}_clients_helper.rb")
+
+      if !options[:test_unit]
+        m.directory File.join('spec')
+        m.directory File.join('spec/models')
+        m.directory File.join('spec/fixtures', class_path)
+        m.directory File.join('spec/controllers', controller_class_path)
+        
+        m.template 'client_application_spec.rb',File.join('spec/models',"client_application_spec.rb")
+        m.template 'oauth_token_spec.rb',    File.join('spec/models',"oauth_token_spec.rb")
+        m.template 'oauth_nonce_spec.rb',    File.join('spec/models',"oauth_nonce_spec.rb")
+        m.template 'client_applications.yml',File.join('spec/fixtures',"client_applications.yml")
+        m.template 'oauth_tokens.yml',    File.join('spec/fixtures',"oauth_tokens.yml")
+        m.template 'oauth_nonces.yml',    File.join('spec/fixtures',"oauth_nonces.yml")
+        m.template 'controller_spec_helper.rb', File.join('spec/controllers', controller_class_path,"#{controller_file_name}_controller_spec_helper.rb")
+        m.template 'controller_spec.rb',File.join('spec/controllers',controller_class_path,"#{controller_file_name}_controller_spec.rb")      
+        m.template 'clients_controller_spec.rb',File.join('spec/controllers',controller_class_path,"#{controller_file_name}_clients_controller_spec.rb")
+      else
+        m.directory File.join('test')
+        m.directory File.join('test/unit')
+        m.directory File.join('test/fixtures', class_path)
+        m.directory File.join('test/functional', controller_class_path)
+        m.template 'client_application_test.rb',File.join('test/unit',"client_application_test.rb")
+        m.template 'oauth_token_test.rb',    File.join('test/unit',"oauth_token_test.rb")
+        m.template 'oauth_nonce_test.rb',    File.join('test/unit',"oauth_nonce_test.rb")
+        m.template 'client_applications.yml',File.join('test/fixtures',"client_applications.yml")
+        m.template 'oauth_tokens.yml',    File.join('test/fixtures',"oauth_tokens.yml")
+        m.template 'oauth_nonces.yml',    File.join('test/fixtures',"oauth_nonces.yml")
+        m.template 'controller_test_helper.rb', File.join('test', controller_class_path,"#{controller_file_name}_controller_test_helper.rb")
+        m.template 'controller_test.rb',File.join('test/functional',controller_class_path,"#{controller_file_name}_controller_test.rb")
+        m.template 'clients_controller_test.rb',File.join('test/functional',controller_class_path,"#{controller_file_name}_clients_controller_test.rb")
+      end
+
+      m.template '_form.html.erb',  File.join('app/views', controller_class_path, 'oauth_clients', "_form.html.erb")
+      m.template 'new.html.erb',  File.join('app/views', controller_class_path, 'oauth_clients', "new.html.erb")
+      m.template 'index.html.erb',  File.join('app/views', controller_class_path, 'oauth_clients', "index.html.erb")
+      m.template 'show.html.erb',  File.join('app/views', controller_class_path, 'oauth_clients', "show.html.erb")
+      m.template 'edit.html.erb',  File.join('app/views', controller_class_path, 'oauth_clients', "edit.html.erb")
+      m.template 'authorize.html.erb',  File.join('app/views', controller_class_path, controller_file_name, "authorize.html.erb")
+      m.template 'authorize_success.html.erb',  File.join('app/views', controller_class_path, controller_file_name, "authorize_success.html.erb")
+      m.template 'authorize_failure.html.erb',  File.join('app/views', controller_class_path, controller_file_name, "authorize_failure.html.erb")
+      
+
+      unless options[:skip_migration]
+        m.migration_template 'migration.rb', 'db/migrate', :assigns => {
+          :migration_name => "CreateOauthTables"
+        }, :migration_file_name => "create_oauth_tables"
+      end
+    end
+  end
+
+  protected
+    def banner
+      "Usage: #{$0} #{spec.name}"
+    end
+
+    def add_options!(opt)
+      opt.separator ''
+      opt.separator 'Options:'
+      opt.on("--skip-migration", 
+             "Don't generate a migration file") { |v| options[:skip_migration] = v }
+      opt.on("--test-unit", 
+             "Generate the Test::Unit compatible tests instead of RSpec") { |v| options[:test_unit] = v }
+    end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/_form.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/_form.html.erb
new file mode 100644 (file)
index 0000000..ee3f5b8
--- /dev/null
@@ -0,0 +1,16 @@
+<div class="field">
+       <label for="client_application_name">Name*</label><br/>
+       <%%= f.text_field :name %>
+</div>
+<div class="field">
+       <label for="client_application_url">Main Application URL*</label><br/>
+       <%%= f.text_field :url %>
+</div>
+<div class="field">
+       <label for="client_application_callback_url">Callback URL*</label><br/>
+       <%%= f.text_field :callback_url %>
+</div>
+<div class="field">
+       <label for="client_application_support_url">Support URL</label><br/>
+       <%%= f.text_field :support_url %>
+</div>
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/access_token.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/access_token.rb
new file mode 100644 (file)
index 0000000..b773310
--- /dev/null
@@ -0,0 +1,10 @@
+class AccessToken<OauthToken
+  validates_presence_of :user
+  before_create :set_authorized_at
+  
+protected 
+  
+  def set_authorized_at
+    self.authorized_at = Time.now
+  end
+end
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize.html.erb
new file mode 100644 (file)
index 0000000..0607eb4
--- /dev/null
@@ -0,0 +1,14 @@
+<h1>Authorize access to your account</h1>
+<p>Would you like to authorize <%%= link_to @token.client_application.name,@token.client_application.url %> (<%%= link_to @token.client_application.url,@token.client_application.url %>) to access your account?</p>
+<%% form_tag authorize_url do %>
+  <%%= hidden_field_tag "oauth_token", @token.token %>
+  <%%- if params[:oauth_callback] -%>
+  <%%= hidden_field_tag "oauth_callback", params[:oauth_callback] %>
+<%%- end -%>
+<p>
+       <%%= check_box_tag 'authorize' %> authorize access
+</p>
+<p>
+       <%%= submit_tag %>
+</p>
+<%% end %>
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize_failure.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize_failure.html.erb
new file mode 100644 (file)
index 0000000..d8110c9
--- /dev/null
@@ -0,0 +1 @@
+<h1>You have disallowed this request</h1>
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize_success.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/authorize_success.html.erb
new file mode 100644 (file)
index 0000000..effe24a
--- /dev/null
@@ -0,0 +1 @@
+<h1>You have allowed this request</h1>
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application.rb
new file mode 100644 (file)
index 0000000..b7ca97d
--- /dev/null
@@ -0,0 +1,54 @@
+require 'oauth'
+class ClientApplication < ActiveRecord::Base
+  belongs_to :user
+  has_many :tokens, :class_name => "OauthToken"
+  validates_presence_of :name, :url, :key, :secret
+  validates_uniqueness_of :key
+  before_validation_on_create :generate_keys
+  
+  def self.find_token(token_key)
+    token = OauthToken.find_by_token(token_key, :include => :client_application)
+    if token && token.authorized?
+      logger.info "Loaded #{token.token} which was authorized by (user_id=#{token.user_id}) on the #{token.authorized_at}"
+      token
+    else
+      nil
+    end
+  end
+  
+  def self.verify_request(request, options = {}, &block)
+    begin
+      signature = OAuth::Signature.build(request, options, &block)
+      logger.info "Signature Base String: #{signature.signature_base_string}"
+      logger.info "Consumer: #{signature.send :consumer_key}"
+      logger.info "Token: #{signature.send :token}"
+      return false unless OauthNonce.remember(signature.request.nonce, signature.request.timestamp)
+      value = signature.verify
+      logger.info "Signature verification returned: #{value.to_s}"
+      value
+    rescue OAuth::Signature::UnknownSignatureMethod => e
+      logger.info "ERROR"+e.to_s
+      false
+    end
+  end
+  
+  def oauth_server
+    @oauth_server ||= OAuth::Server.new("http://your.site")
+  end
+  
+  def credentials
+    @oauth_client ||= OAuth::Consumer.new(key, secret)
+  end
+    
+  def create_request_token
+    RequestToken.create :client_application => self
+  end
+  
+protected
+  
+  def generate_keys
+    @oauth_client = oauth_server.generate_consumer_credentials
+    self.key = @oauth_client.key
+    self.secret = @oauth_client.secret
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application_spec.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application_spec.rb
new file mode 100644 (file)
index 0000000..14f3887
--- /dev/null
@@ -0,0 +1,60 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+module OAuthSpecHelpers
+  
+  def create_consumer
+    @consumer = OAuth::Consumer.new(@application.key,@application.secret,
+      {
+        :site => @application.oauth_server.base_url
+      })
+  end
+  
+  def create_test_request
+    
+  end
+  
+  def create_oauth_request
+    @token = AccessToken.create :client_application => @application, :user => users(:quentin)
+    @request = @consumer.create_signed_request(:get, "/hello", @token)
+  end
+  
+  def create_request_token_request
+    @request = @consumer.create_signed_request(:get, @application.oauth_server.request_token_path, @token)
+  end
+  
+  def create_access_token_request
+    @token = RequestToken.create :client_application => @application
+    @request = @consumer.create_signed_request(:get, @application.oauth_server.request_token_path, @token)
+  end
+  
+end
+
+describe ClientApplication do #, :shared => true do
+  include OAuthSpecHelpers
+  fixtures :users, :client_applications, :oauth_tokens
+  before(:each) do
+    @application = ClientApplication.create :name => "Agree2", :url => "http://agree2.com", :user => users(:quentin)
+    create_consumer
+  end
+
+  it "should be valid" do
+    @application.should be_valid
+  end
+  
+    
+  it "should not have errors" do
+    @application.errors.full_messages.should == []
+  end
+  
+  it "should have key and secret" do
+    @application.key.should_not be_nil
+    @application.secret.should_not be_nil
+  end
+
+  it "should have credentials" do
+    @application.credentials.should_not be_nil
+    @application.credentials.key.should == @application.key
+    @application.credentials.secret.should == @application.secret
+  end
+  
+end
+
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application_test.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_application_test.rb
new file mode 100644 (file)
index 0000000..3ba2cf7
--- /dev/null
@@ -0,0 +1,42 @@
+require File.dirname(__FILE__) + '/../test_helper'
+module OAuthHelpers
+  
+  def create_consumer
+    @consumer=OAuth::Consumer.new(@application.key,@application.secret,
+      {
+        :site=>@application.oauth_server.base_url
+      })
+  end
+  
+end
+
+class ClientApplicationTest < ActiveSupport::TestCase
+  include OAuthHelpers
+  fixtures :users,:client_applications,:oauth_tokens
+  
+  def setup
+    @application = ClientApplication.create :name=>"Agree2",:url=>"http://agree2.com",:user=>users(:quentin)
+    create_consumer
+  end
+
+  def test_should_be_valid
+    assert @application.valid?
+  end
+  
+    
+  def test_should_not_have_errors
+    assert_equal [], @application.errors.full_messages
+  end
+  
+  def test_should_have_key_and_secret
+    assert_not_nil @application.key
+    assert_not_nil @application.secret
+  end
+
+  def test_should_have_credentials
+    assert_not_nil @application.credentials
+    assert_equal @application.key, @application.credentials.key
+    assert_equal @application.secret, @application.credentials.secret
+  end
+  
+end
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_applications.yml b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/client_applications.yml
new file mode 100644 (file)
index 0000000..4bbf370
--- /dev/null
@@ -0,0 +1,23 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+one:
+  id: 1
+  name: MyString
+  url: MyString
+  support_url: MyString
+  callback_url: MyString
+  key: one_key
+  secret: MyString
+  user_id: 1
+  created_at: 2007-11-17 16:56:51
+  updated_at: 2007-11-17 16:56:51
+two:
+  id: 2
+  name: MyString
+  url: MyString
+  support_url: MyString
+  callback_url: MyString
+  key: two_key
+  secret: MyString
+  user_id: 1
+  created_at: 2007-11-17 16:56:51
+  updated_at: 2007-11-17 16:56:51
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller.rb
new file mode 100644 (file)
index 0000000..5f78274
--- /dev/null
@@ -0,0 +1,47 @@
+class OauthClientsController < ApplicationController
+  before_filter :login_required
+  
+  def index
+    @client_applications = current_user.client_applications
+    @tokens = current_user.tokens.find :all, :conditions => 'oauth_tokens.invalidated_at is null and oauth_tokens.authorized_at is not null'
+  end
+
+  def new
+    @client_application = ClientApplication.new
+  end
+
+  def create
+    @client_application = current_user.client_applications.build(params[:client_application])
+    if @client_application.save
+      flash[:notice] = "Registered the information successfully"
+      redirect_to :action => "show", :id => @client_application.id
+    else
+      render :action => "new"
+    end
+  end
+  
+  def show
+    @client_application = current_user.client_applications.find(params[:id])
+  end
+
+  def edit
+    @client_application = current_user.client_applications.find(params[:id])
+  end
+  
+  def update
+    @client_application = current_user.client_applications.find(params[:id])
+    if @client_application.update_attributes(params[:client_application])
+      flash[:notice] = "Updated the client information successfully"
+      redirect_to :action => "show", :id => @client_application.id
+    else
+      render :action => "edit"
+    end
+  end
+
+  def destroy
+    @client_application = current_user.client_applications.find(params[:id])
+    @client_application.destroy
+    flash[:notice] = "Destroyed the client application registration"
+    redirect_to :action => "index"
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller_spec.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller_spec.rb
new file mode 100644 (file)
index 0000000..d617b56
--- /dev/null
@@ -0,0 +1,239 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require File.dirname(__FILE__) + '/oauth_controller_spec_helper'
+require 'oauth/client/action_controller_request'
+
+describe OauthClientsController, "index" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    login_as_application_owner
+  end
+  
+  def do_get
+    get :index
+  end
+  
+  it "should be successful" do
+    do_get
+    response.should be_success
+  end
+  
+  it "should query current_users client applications" do
+    @user.should_receive(:client_applications).and_return(@client_applications)
+    do_get
+  end
+  
+  it "should assign client_applications" do
+    do_get
+    assigns[:client_applications].should equal(@client_applications)
+  end
+  
+  it "should render index template" do
+    do_get
+    response.should render_template('index')
+  end
+end
+
+describe OauthClientsController, "show" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    login_as_application_owner
+  end
+  
+  def do_get
+    get :show, :id => '3'
+  end
+  
+  it "should be successful" do
+    do_get
+    response.should be_success
+  end
+  
+  it "should query current_users client applications" do
+    @user.should_receive(:client_applications).and_return(@client_applications)
+    @client_applications.should_receive(:find).with('3').and_return(@client_application)
+    do_get
+  end
+  
+  it "should assign client_applications" do
+    do_get
+    assigns[:client_application].should equal(@client_application)
+  end
+  
+  it "should render show template" do
+    do_get
+    response.should render_template('show')
+  end
+  
+end
+
+describe OauthClientsController, "new" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    login_as_application_owner
+    ClientApplication.stub!(:new).and_return(@client_application)
+  end
+  
+  def do_get
+    get :new
+  end
+  
+  it "should be successful" do
+    do_get
+    response.should be_success
+  end
+  
+  it "should assign client_applications" do
+    do_get
+    assigns[:client_application].should equal(@client_application)
+  end
+  
+  it "should render show template" do
+    do_get
+    response.should render_template('new')
+  end
+  
+end
+
+describe OauthClientsController, "edit" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    login_as_application_owner
+  end
+  
+  def do_get
+    get :edit, :id => '3'
+  end
+  
+  it "should be successful" do
+    do_get
+    response.should be_success
+  end
+  
+  it "should query current_users client applications" do
+    @user.should_receive(:client_applications).and_return(@client_applications)
+    @client_applications.should_receive(:find).with('3').and_return(@client_application)
+    do_get
+  end
+  
+  it "should assign client_applications" do
+    do_get
+    assigns[:client_application].should equal(@client_application)
+  end
+  
+  it "should render edit template" do
+    do_get
+    response.should render_template('edit')
+  end
+  
+end
+
+describe OauthClientsController, "create" do
+  include OAuthControllerSpecHelper
+  
+  before(:each) do
+    login_as_application_owner
+    @client_applications.stub!(:build).and_return(@client_application)
+    @client_application.stub!(:save).and_return(true)
+  end
+  
+  def do_valid_post
+    @client_application.should_receive(:save).and_return(true)
+    post :create, 'client_application'=>{'name' => 'my site'}
+  end
+
+  def do_invalid_post
+    @client_application.should_receive(:save).and_return(false)
+    post :create, :client_application=>{:name => 'my site'}
+  end
+  
+  it "should query current_users client applications" do
+    @client_applications.should_receive(:build).and_return(@client_application)
+    do_valid_post
+  end
+  
+  it "should redirect to new client_application" do
+    do_valid_post
+    response.should be_redirect
+    response.should redirect_to(:action => "show", :id => @client_application.id)
+  end
+  
+  it "should assign client_applications" do
+    do_invalid_post
+    assigns[:client_application].should equal(@client_application)
+  end
+  
+  it "should render show template" do
+    do_invalid_post
+    response.should render_template('new')
+  end
+end
+
+describe OauthClientsController, "destroy" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    login_as_application_owner
+    @client_application.stub!(:destroy)
+  end
+  
+  def do_delete
+    delete :destroy, :id => '3'
+  end
+    
+  it "should query current_users client applications" do
+    @user.should_receive(:client_applications).and_return(@client_applications)
+    @client_applications.should_receive(:find).with('3').and_return(@client_application)
+    do_delete
+  end
+
+  it "should destroy client applications" do
+    @client_application.should_receive(:destroy)
+    do_delete
+  end
+    
+  it "should redirect to list" do
+    do_delete
+    response.should be_redirect
+    response.should redirect_to(:action => 'index')
+  end
+  
+end
+
+describe OauthClientsController, "update" do
+  include OAuthControllerSpecHelper
+  
+  before(:each) do
+    login_as_application_owner
+  end
+  
+  def do_valid_update
+    @client_application.should_receive(:update_attributes).and_return(true)
+    put :update, :id => '1', 'client_application'=>{'name' => 'my site'}
+  end
+
+  def do_invalid_update
+    @client_application.should_receive(:update_attributes).and_return(false)
+    put :update, :id => '1', 'client_application'=>{'name' => 'my site'}
+  end
+  
+  it "should query current_users client applications" do
+    @user.should_receive(:client_applications).and_return(@client_applications)
+    @client_applications.should_receive(:find).with('1').and_return(@client_application)
+    do_valid_update
+  end
+  
+  it "should redirect to new client_application" do
+    do_valid_update
+    response.should be_redirect
+    response.should redirect_to(:action => "show", :id => @client_application.id)
+  end
+  
+  it "should assign client_applications" do
+    do_invalid_update
+    assigns[:client_application].should equal(@client_application)
+  end
+  
+  it "should render show template" do
+    do_invalid_update
+    response.should render_template('edit')
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller_test.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_controller_test.rb
new file mode 100644 (file)
index 0000000..47585a2
--- /dev/null
@@ -0,0 +1,280 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/../oauth_controller_test_helper'
+require 'oauth/client/action_controller_request'
+
+class OauthClientsController; def rescue_action(e) raise e end; end
+
+class OauthClientsControllerIndexTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthClientsController
+  
+  def setup    
+    @controller = OauthClientsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new    
+    
+    login_as_application_owner
+  end
+  
+  def do_get
+    get :index
+  end
+  
+  def test_should_be_successful
+    do_get
+    assert @response.success?
+  end
+  
+  def test_should_query_current_users_client_applications
+    @user.expects(:client_applications).returns(@client_applications)
+    do_get
+  end
+  
+  def test_should_assign_client_applications
+    do_get
+    assert_equal @client_applications, assigns(:client_applications)
+  end
+  
+  def test_should_render_index_template
+    do_get
+    assert_template 'index'
+  end
+end
+
+class OauthClientsControllerShowTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthClientsController
+  
+  def setup
+    @controller = OauthClientsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new    
+    
+    login_as_application_owner
+  end
+  
+  def do_get
+    get :show, :id=>'3'
+  end
+  
+  def test_should_be_successful
+    do_get
+    assert @response.success?
+  end
+  
+  def test_should_query_current_users_client_applications
+    @user.expects(:client_applications).returns(@client_applications)
+    @client_applications.expects(:find).with('3').returns(@client_application)
+    do_get
+  end
+  
+  def test_should_assign_client_applications
+    do_get
+    assert_equal @client_application, assigns(:client_application)
+  end
+  
+  def test_should_render_show_template
+    do_get
+    assert_template 'show'
+  end
+  
+end
+
+class OauthClientsControllerNewTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthClientsController
+
+  def setup
+    @controller = OauthClientsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new    
+    
+    login_as_application_owner
+    ClientApplication.stubs(:new).returns(@client_application)
+  end
+  
+  def do_get
+    get :new
+  end
+  
+  def test_should_be_successful
+    do_get
+    assert @response.success?
+  end
+  
+  def test_should_assign_client_applications
+    do_get
+    assert_equal @client_application, assigns(:client_application)
+  end
+  
+  def test_should_render_show_template
+    do_get
+    assert_template 'new'
+  end
+  
+end
+class OauthClientsControllerEditTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthClientsController
+  
+  def setup
+    @controller = OauthClientsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new    
+
+    login_as_application_owner
+  end
+  
+  def do_get
+    get :edit, :id=>'3'
+  end
+  
+  def test_should_be_successful
+    do_get
+    assert @response.success?
+  end
+  
+  def test_should_query_current_users_client_applications
+    @user.expects(:client_applications).returns(@client_applications)
+    @client_applications.expects(:find).with('3').returns(@client_application)
+    do_get
+  end
+  
+  def test_should_assign_client_applications
+    do_get
+    assert_equal @client_application, assigns(:client_application)
+  end
+  
+  def test_should_render_edit_template
+    do_get
+    assert_template 'edit'
+  end
+  
+end
+
+class OauthClientsControllerCreateTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthClientsController
+  
+  def setup
+    @controller = OauthClientsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new    
+    
+    login_as_application_owner
+    @client_applications.stubs(:build).returns(@client_application)
+    @client_application.stubs(:save).returns(true)
+  end
+  
+  def do_valid_post
+    @client_application.expects(:save).returns(true)
+    post :create,'client_application'=>{'name'=>'my site'}
+  end
+
+  def do_invalid_post
+    @client_application.expects(:save).returns(false)
+    post :create,:client_application=>{:name=>'my site'}
+  end
+  
+  def test_should_query_current_users_client_applications
+    @client_applications.expects(:build).returns(@client_application)
+    do_valid_post
+  end
+  
+  def test_should_redirect_to_new_client_application
+    do_valid_post
+    assert_response :redirect
+    assert_redirected_to(:action => "show", :id => @client_application.id)
+  end
+  
+  def test_should_assign_client_applications
+    do_invalid_post
+    assert_equal @client_application, assigns(:client_application)
+  end
+  
+  def test_should_render_show_template
+    do_invalid_post
+    assert_template('new')
+  end
+end
+class OauthClientsControllerDestroyTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthClientsController
+  
+  def setup
+    @controller = OauthClientsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+    
+    login_as_application_owner
+    @client_application.stubs(:destroy)
+  end
+  
+  def do_delete
+    delete :destroy,:id=>'3'
+  end
+    
+  def test_should_query_current_users_client_applications
+    @user.expects(:client_applications).returns(@client_applications)
+    @client_applications.expects(:find).with('3').returns(@client_application)
+    do_delete
+  end
+
+  def test_should_destroy_client_applications
+    @client_application.expects(:destroy)
+    do_delete
+  end
+    
+  def test_should_redirect_to_list
+    do_delete
+    assert_response :redirect
+    assert_redirected_to :action => 'index'
+  end
+  
+end
+
+class OauthClientsControllerUpdateTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthClientsController
+
+  def setup
+    @controller = OauthClientsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+    login_as_application_owner
+  end
+  
+  def do_valid_update
+    @client_application.expects(:update_attributes).returns(true)
+    put :update, :id => '1', 'client_application' => {'name'=>'my site'}
+  end
+
+  def do_invalid_update
+    @client_application.expects(:update_attributes).returns(false)
+    put :update, :id=>'1', 'client_application' => {'name'=>'my site'}
+  end
+  
+  def test_should_query_current_users_client_applications
+    @user.expects(:client_applications).returns(@client_applications)
+    @client_applications.expects(:find).with('1').returns(@client_application)
+    do_valid_update
+  end
+  
+  def test_should_redirect_to_new_client_application
+    do_valid_update
+    assert_response :redirect
+    assert_redirected_to :action => "show", :id => @client_application.id
+  end
+  
+  def test_should_assign_client_applications
+    do_invalid_update
+    assert_equal @client_application, assigns(:client_application)
+  end
+  
+  def test_should_render_show_template
+    do_invalid_update
+    assert_template('edit')
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_helper.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/clients_helper.rb
new file mode 100644 (file)
index 0000000..3b909aa
--- /dev/null
@@ -0,0 +1,2 @@
+module OauthClientsHelper
+end
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller.rb
new file mode 100644 (file)
index 0000000..58ac213
--- /dev/null
@@ -0,0 +1,62 @@
+class OauthController < ApplicationController
+  before_filter :login_required, :except => [:request_token, :access_token, :test_request]
+  before_filter :login_or_oauth_required, :only => [:test_request]
+  before_filter :verify_oauth_consumer_signature, :only => [:request_token]
+  before_filter :verify_oauth_request_token, :only => [:access_token]
+  # Uncomment the following if you are using restful_open_id_authentication
+  # skip_before_filter :verify_authenticity_token
+
+  def request_token
+    @token = current_client_application.create_request_token
+    if @token
+      render :text => @token.to_query
+    else
+      render :nothing => true, :status => 401
+    end
+  end 
+  
+  def access_token
+    @token = current_token && current_token.exchange!
+    if @token
+      render :text => @token.to_query
+    else
+      render :nothing => true, :status => 401
+    end
+  end
+
+  def test_request
+    render :text => params.collect{|k,v|"#{k}=#{v}"}.join("&")
+  end
+  
+  def authorize
+    @token = RequestToken.find_by_token params[:oauth_token]
+    unless @token.invalidated?    
+      if request.post? 
+        if params[:authorize] == '1'
+          @token.authorize!(current_user)
+          redirect_url = params[:oauth_callback] || @token.client_application.callback_url
+          if redirect_url
+            redirect_to "#{redirect_url}?oauth_token=#{@token.token}"
+          else
+            render :action => "authorize_success"
+          end
+        elsif params[:authorize] == "0"
+          @token.invalidate!
+          render :action => "authorize_failure"
+        end
+      end
+    else
+      render :action => "authorize_failure"
+    end
+  end
+  
+  def revoke
+    @token = current_user.tokens.find_by_token params[:token]
+    if @token
+      @token.invalidate!
+      flash[:notice] = "You've revoked the token for #{@token.client_application.name}"
+    end
+    redirect_to oauth_clients_url
+  end
+  
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_spec.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_spec.rb
new file mode 100644 (file)
index 0000000..f3479ab
--- /dev/null
@@ -0,0 +1,296 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require File.dirname(__FILE__) + '/oauth_controller_spec_helper'
+require 'oauth/client/action_controller_request'
+
+describe OauthController, "getting a request token" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    setup_oauth
+    sign_request_with_oauth
+    @client_application.stub!(:create_request_token).and_return(@request_token)
+  end
+  
+  def do_get
+    get :request_token
+  end
+  
+  it "should be successful" do
+    do_get
+    response.should be_success
+  end
+  
+  it "should query for client_application" do
+    ClientApplication.should_receive(:find_by_key).with('key').and_return(@client_application)
+    do_get
+  end
+  
+  it "should request token from client_application" do
+    @client_application.should_receive(:create_request_token).and_return(@request_token)
+    do_get
+  end
+  
+  it "should return token string" do
+    do_get
+    response.body.should == @request_token_string
+  end
+end
+
+describe OauthController, "token authorization" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    login
+    setup_oauth
+    RequestToken.stub!(:find_by_token).and_return(@request_token)
+  end
+  
+  def do_get
+    get :authorize, :oauth_token => @request_token.token
+  end
+
+  def do_post
+    @request_token.should_receive(:authorize!).with(@user)
+    post :authorize, :oauth_token => @request_token.token, :authorize => "1"
+  end
+
+  def do_post_without_user_authorization
+    @request_token.should_receive(:invalidate!)
+    post :authorize, :oauth_token => @request_token.token, :authorize => "0"
+  end
+
+  def do_post_with_callback
+    @request_token.should_receive(:authorize!).with(@user)
+    post :authorize, :oauth_token => @request_token.token, :oauth_callback => "http://application/alternative", :authorize => "1"
+  end
+
+  def do_post_with_no_application_callback
+    @request_token.should_receive(:authorize!).with(@user)
+    @client_application.stub!(:callback_url).and_return(nil)
+    post :authorize, :oauth_token => @request_token.token, :authorize => "1"
+  end
+  
+  it "should be successful" do
+    do_get
+    response.should be_success
+  end
+  
+  it "should query for client_application" do
+    RequestToken.should_receive(:find_by_token).and_return(@request_token)
+    do_get
+  end
+  
+  it "should assign token" do
+    do_get
+    assigns[:token].should equal(@request_token)
+  end
+  
+  it "should render authorize template" do
+    do_get
+    response.should render_template('authorize')
+  end
+  
+  it "should redirect to default callback" do
+    do_post
+    response.should be_redirect
+    response.should redirect_to("http://application/callback?oauth_token=#{@request_token.token}")
+  end
+
+  it "should redirect to callback in query" do
+    do_post_with_callback
+    response.should be_redirect
+    response.should redirect_to("http://application/alternative?oauth_token=#{@request_token.token}")
+  end
+
+  it "should be successful on authorize without any application callback" do
+    do_post_with_no_application_callback
+    response.should be_success
+  end
+
+  it "should be successful on authorize without any application callback" do
+    do_post_with_no_application_callback
+    response.should render_template('authorize_success')
+  end
+  
+  it "should render failure screen on user invalidation" do
+    do_post_without_user_authorization
+    response.should render_template('authorize_failure')
+  end
+
+  it "should render failure screen if token is invalidated" do
+    @request_token.should_receive(:invalidated?).and_return(true)
+    do_get
+    response.should render_template('authorize_failure')
+  end
+  
+
+end
+
+
+describe OauthController, "getting an access token" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    setup_oauth
+    sign_request_with_oauth @request_token
+    @request_token.stub!(:exchange!).and_return(@access_token)
+  end
+  
+  def do_get
+    get :access_token
+  end
+  
+  it "should be successful" do
+    do_get
+    response.should be_success
+  end
+  
+  it "should query for client_application" do
+    ClientApplication.should_receive(:find_token).with(@request_token.token).and_return(@request_token)
+    do_get
+  end
+  
+  it "should request token from client_application" do
+    @request_token.should_receive(:exchange!).and_return(@access_token)
+    do_get
+  end
+  
+  it "should return token string" do
+    do_get
+    response.body.should == @access_token_string
+  end
+end
+
+class OauthorizedController<ApplicationController
+  before_filter :login_or_oauth_required, :only => :both
+  before_filter :login_required, :only => :interactive
+  before_filter :oauth_required, :only => :token_only
+  
+  def interactive
+  end
+  
+  def token_only
+  end
+  
+  def both
+  end
+end
+
+describe OauthorizedController, " access control" do
+  include OAuthControllerSpecHelper
+  
+  before(:each) do
+  end
+  
+  it "should have access_token set up correctly" do
+    setup_to_authorize_request
+    @access_token.is_a?(AccessToken).should == true
+    @access_token.should be_authorized
+    @access_token.should_not be_invalidated
+    @access_token.user.should == @user
+    @access_token.client_application.should == @client_application
+  end
+  
+  it "should return false for oauth? by default" do
+    controller.send(:oauth?).should == false
+  end
+
+  it "should return nil for current_token  by default" do
+    controller.send(:current_token).should be_nil
+  end
+  
+  it "should allow oauth when using login_or_oauth_required" do
+    setup_to_authorize_request
+    sign_request_with_oauth(@access_token)
+    ClientApplication.should_receive(:find_token).with(@access_token.token).and_return(@access_token)
+    get :both
+    controller.send(:current_token).should == @access_token
+    controller.send(:current_token).is_a?(AccessToken).should == true 
+    controller.send(:current_user).should == @user
+    controller.send(:current_client_application).should == @client_application
+    response.code.should == '200'
+    response.should be_success
+  end
+
+  it "should allow interactive when using login_or_oauth_required" do
+    login
+    get :both
+    response.should be_success
+    controller.send(:current_user).should == @user
+    controller.send(:current_token).should be_nil
+  end
+
+  
+  it "should allow oauth when using oauth_required" do
+    setup_to_authorize_request
+    sign_request_with_oauth(@access_token)
+    ClientApplication.should_receive(:find_token).with(@access_token.token).and_return(@access_token)
+    get :token_only
+    controller.send(:current_token).should == @access_token
+    controller.send(:current_client_application).should == @client_application
+    controller.send(:current_user).should == @user 
+    response.code.should == '200' 
+    response.should be_success 
+  end
+
+  it "should disallow oauth using RequestToken when using oauth_required" do
+    setup_to_authorize_request
+    ClientApplication.should_receive(:find_token).with(@request_token.token).and_return(@request_token)
+    sign_request_with_oauth(@request_token)
+    get :token_only
+    response.code.should == '401'
+  end
+
+  it "should disallow interactive when using oauth_required" do
+    login
+    get :token_only
+    response.code.should == '401'
+    
+    controller.send(:current_user).should == @user
+    controller.send(:current_token).should be_nil
+  end
+
+  it "should disallow oauth when using login_required" do
+    setup_to_authorize_request
+    sign_request_with_oauth(@access_token)
+    get :interactive
+    response.code.should == "302"
+    controller.send(:current_user).should be_nil
+    controller.send(:current_token).should be_nil
+  end
+
+  it "should allow interactive when using login_required" do
+    login
+    get :interactive
+    response.should be_success
+    controller.send(:current_user).should == @user
+    controller.send(:current_token).should be_nil
+  end
+
+end
+
+describe OauthController, "revoke" do
+  include OAuthControllerSpecHelper
+  before(:each) do
+    setup_oauth_for_user
+    @request_token.stub!(:invalidate!)
+  end
+  
+  def do_post
+    post :revoke, :token => "TOKEN STRING"
+  end
+  
+  it "should redirect to index" do
+    do_post
+    response.should be_redirect
+    response.should redirect_to('http://test.host/oauth_clients')
+  end
+  
+  it "should query current_users tokens" do
+    @tokens.should_receive(:find_by_token).and_return(@request_token)
+    do_post
+  end
+  
+  it "should call invalidate on token" do
+    @request_token.should_receive(:invalidate!)
+    do_post
+  end
+  
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_spec_helper.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_spec_helper.rb
new file mode 100644 (file)
index 0000000..9e71284
--- /dev/null
@@ -0,0 +1,74 @@
+module OAuthControllerSpecHelper
+  def login
+    controller.stub!(:local_request?).and_return(true)
+    @user = mock_model(User)
+    controller.stub!(:current_user).and_return(@user)
+    @tokens = []
+    @tokens.stub!(:find).and_return(@tokens)
+    @user.stub!(:tokens).and_return(@tokens)
+    User.stub!(:find_by_id).and_return(@user)
+  end
+  
+  def login_as_application_owner
+    login
+    @client_application = mock_model(ClientApplication)
+    @client_applications = [@client_application]
+    
+    @user.stub!(:client_applications).and_return(@client_applications)
+    @client_applications.stub!(:find).and_return(@client_application)
+  end
+  
+  def setup_oauth
+    controller.stub!(:local_request?).and_return(true)
+    @user||=mock_model(User)
+    
+    User.stub!(:find_by_id).and_return(@user)
+    
+    @server = OAuth::Server.new "http://test.host"
+    @consumer = OAuth::Consumer.new('key', 'secret',{:site => "http://test.host"})
+
+    @client_application = mock_model(ClientApplication)
+    controller.stub!(:current_client_application).and_return(@client_application)
+    ClientApplication.stub!(:find_by_key).and_return(@client_application)
+    @client_application.stub!(:key).and_return(@consumer.key)
+    @client_application.stub!(:secret).and_return(@consumer.secret)
+    @client_application.stub!(:name).and_return("Client Application name")
+    @client_application.stub!(:callback_url).and_return("http://application/callback")
+    @request_token = mock_model(RequestToken, :token => 'request_token', :client_application => @client_application, :secret => "request_secret", :user => @user)
+    @request_token.stub!(:invalidated?).and_return(false)
+    ClientApplication.stub!(:find_token).and_return(@request_token)
+    
+    @request_token_string = "oauth_token = request_token&oauth_token_secret = request_secret"
+    @request_token.stub!(:to_query).and_return(@request_token_string)
+
+    @access_token = mock_model(AccessToken, :token => 'access_token', :client_application => @client_application, :secret => "access_secret", :user => @user)
+    @access_token.stub!(:invalidated?).and_return(false)
+    @access_token.stub!(:authorized?).and_return(true)
+    @access_token_string = "oauth_token = access_token&oauth_token_secret = access_secret"
+    @access_token.stub!(:to_query).and_return(@access_token_string)
+
+    @client_application.stub!(:authorize_request?).and_return(true)
+#    @client_application.stub!(:sign_request_with_oauth_token).and_return(@request_token)
+    @client_application.stub!(:exchange_for_access_token).and_return(@access_token)
+  end
+  
+  def setup_oauth_for_user
+    login
+    setup_oauth
+    @tokens = [@request_token]
+    @tokens.stub!(:find).and_return(@tokens)
+    @tokens.stub!(:find_by_token).and_return(@request_token)
+    @user.stub!(:tokens).and_return(@tokens)
+  end
+  
+  def sign_request_with_oauth(token = nil)
+    ActionController::TestRequest.use_oauth = true
+    @request.configure_oauth(@consumer,token)
+  end
+    
+  def setup_to_authorize_request
+    setup_oauth
+    OauthToken.stub!(:find_by_token).with( @access_token.token).and_return(@access_token)
+    @access_token.stub!(:is_a?).and_return(true)
+  end
+end
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_test.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_test.rb
new file mode 100644 (file)
index 0000000..f75eaee
--- /dev/null
@@ -0,0 +1,310 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/../oauth_controller_test_helper'
+require 'oauth/client/action_controller_request'
+
+class OauthController; def rescue_action(e) raise e end; end
+
+class OauthControllerRequestTokenTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthController
+  
+  def setup
+    @controller = OauthController.new
+    setup_oauth
+    sign_request_with_oauth
+    @client_application.stubs(:create_request_token).returns(@request_token)
+  end
+  
+  def do_get
+    get :request_token
+  end
+  
+  def test_should_be_successful
+    do_get
+    assert @response.success?
+  end
+  
+  def test_should_query_for_client_application
+    ClientApplication.expects(:find_by_key).with('key').returns(@client_application)
+    do_get
+  end
+  
+  def test_should_request_token_from_client_application
+    @client_application.expects(:create_request_token).returns(@request_token)
+    do_get
+  end
+  
+  def test_should_return_token_string
+    do_get
+    assert_equal @request_token_string, @response.body
+  end
+end
+
+class OauthControllerTokenAuthorizationTest < ActionController::TestCase
+   include OAuthControllerTestHelper
+   tests OauthController
+   
+  def setup
+    @controller = OauthController.new
+    login
+    setup_oauth
+    RequestToken.stubs(:find_by_token).returns(@request_token)
+  end
+  
+  def do_get
+    get :authorize, :oauth_token => @request_token.token
+  end
+
+  def do_post
+    @request_token.expects(:authorize!).with(@user)
+    post :authorize,:oauth_token=>@request_token.token,:authorize=>"1"
+  end
+
+  def do_post_without_user_authorization
+    @request_token.expects(:invalidate!)
+    post :authorize,:oauth_token=>@request_token.token,:authorize=>"0"
+  end
+
+  def do_post_with_callback
+    @request_token.expects(:authorize!).with(@user)
+    post :authorize,:oauth_token=>@request_token.token,:oauth_callback=>"http://application/alternative",:authorize=>"1"
+  end
+
+  def do_post_with_no_application_callback
+    @request_token.expects(:authorize!).with(@user)
+    @client_application.stubs(:callback_url).returns(nil)
+    post :authorize, :oauth_token => @request_token.token, :authorize=>"1"
+  end
+  
+  def test_should_be_successful
+    do_get
+    assert @response.success?
+  end
+  
+  def test_should_query_for_client_application
+    RequestToken.expects(:find_by_token).returns(@request_token)
+    do_get
+  end
+  
+  def test_should_assign_token
+    do_get
+    assert_equal @request_token, assigns(:token)
+  end
+  
+  def test_should_render_authorize_template
+    do_get
+    assert_template('authorize')
+  end
+  
+  def test_should_redirect_to_default_callback
+    do_post
+    assert_response :redirect
+    assert_redirected_to("http://application/callback?oauth_token=#{@request_token.token}")
+  end
+
+  def test_should_redirect_to_callback_in_query
+    do_post_with_callback
+    assert_response :redirect
+    assert_redirected_to("http://application/alternative?oauth_token=#{@request_token.token}")
+  end
+
+  def test_should_be_successful_on_authorize_without_any_application_callback
+    do_post_with_no_application_callback
+    assert @response.success?
+    assert_template('authorize_success')
+  end
+  
+  def test_should_render_failure_screen_on_user_invalidation
+    do_post_without_user_authorization
+    assert_template('authorize_failure')
+  end
+
+  def test_should_render_failure_screen_if_token_is_invalidated
+    @request_token.expects(:invalidated?).returns(true)
+    do_get
+    assert_template('authorize_failure')
+  end
+  
+
+end
+
+class OauthControllerGetAccessTokenTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthController
+  
+  def setup
+    @controller = OauthController.new
+    setup_oauth
+    sign_request_with_oauth @request_token
+    @request_token.stubs(:exchange!).returns(@access_token)
+  end
+  
+  def do_get
+    get :access_token
+  end
+  
+  def test_should_be_successful
+    do_get
+    assert @response.success?
+  end
+  
+  def test_should_query_for_client_application
+    ClientApplication.expects(:find_token).with(@request_token.token).returns(@request_token)
+    do_get
+  end
+  
+  def test_should_request_token_from_client_application
+    @request_token.expects(:exchange!).returns(@access_token)
+    do_get
+  end
+  
+  def test_should__return_token_string
+    do_get
+    assert_equal @access_token_string, @response.body
+  end
+end
+
+class OauthorizedController < ApplicationController
+  before_filter :login_or_oauth_required,:only=>:both
+  before_filter :login_required,:only=>:interactive
+  before_filter :oauth_required,:only=>:token_only
+    
+  def interactive
+    render :text => "interactive"
+  end
+  
+  def token_only
+    render :text => "token"
+  end
+  
+  def both
+    render :text => "both"
+  end
+end
+
+class OauthControllerAccessControlTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthorizedController
+  
+  def setup
+    @controller = OauthorizedController.new
+  end
+  
+  def test_should__have_access_token_set_up_correctly
+    setup_to_authorize_request
+    assert @access_token.is_a?(AccessToken)
+    assert @access_token.authorized?
+    assert !@access_token.invalidated?
+    assert_equal @user, @access_token.user
+    assert_equal @client_application, @access_token.client_application
+  end
+  
+  def test_should_return_false_for_oauth_by_default
+    assert_equal false, @controller.send(:oauth?)
+  end
+
+  def test_should_return_nil_for_current_token_by_default
+    assert_nil @controller.send(:current_token)
+  end
+  
+  def test_should_allow_oauth_when_using_login_or_oauth_required
+    setup_to_authorize_request
+    sign_request_with_oauth(@access_token)
+    ClientApplication.expects(:find_token).with(@access_token.token).returns(@access_token)
+    get :both
+    assert_equal @access_token, @controller.send(:current_token)
+    assert @controller.send(:current_token).is_a?(AccessToken)
+    assert_equal @user, @controller.send(:current_user)
+    assert_equal @client_application, @controller.send(:current_client_application)
+    assert_equal '200', @response.code
+    assert @response.success?
+  end
+
+  def test_should_allow_interactive_when_using_login_or_oauth_required
+    login
+    get :both
+    assert @response.success?
+    assert_equal @user, @controller.send(:current_user)
+    assert_nil @controller.send(:current_token)
+  end
+  
+  def test_should_allow_oauth_when_using_oauth_required
+    setup_to_authorize_request
+    sign_request_with_oauth(@access_token)
+    ClientApplication.expects(:find_token).with(@access_token.token).returns(@access_token)
+    get :token_only
+    assert_equal @access_token, @controller.send(:current_token)
+    assert_equal @client_application, @controller.send(:current_client_application)
+    assert_equal @user, @controller.send(:current_user)
+    assert_equal '200', @response.code
+    assert @response.success? 
+  end
+
+  def test_should_disallow_oauth_using_request_token_when_using_oauth_required
+    setup_to_authorize_request
+    ClientApplication.expects(:find_token).with(@request_token.token).returns(@request_token)
+    sign_request_with_oauth(@request_token)
+    get :token_only
+    assert_equal '401', @response.code
+  end
+
+  def test_should_disallow_interactive_when_using_oauth_required
+    login
+    get :token_only
+    assert_equal '401', @response.code
+    
+    assert_equal @user, @controller.send(:current_user)
+    assert_nil @controller.send(:current_token)
+  end
+
+  def test_should_disallow_oauth_when_using_login_required
+    setup_to_authorize_request
+    sign_request_with_oauth(@access_token)
+    get :interactive
+    assert_equal "302",@response.code
+    assert_nil @controller.send(:current_user)
+    assert_nil @controller.send(:current_token)
+  end
+
+  def test_should_allow_interactive_when_using_login_required
+    login
+    get :interactive
+    assert @response.success?
+    assert_equal @user, @controller.send(:current_user)
+    assert_nil @controller.send(:current_token)
+  end
+
+end
+
+class OauthControllerRevokeTest < ActionController::TestCase
+  include OAuthControllerTestHelper
+  tests OauthController
+  
+  def setup
+    @controller = OauthController.new
+    setup_oauth_for_user
+    @request_token.stubs(:invalidate!)
+  end
+  
+  def do_post
+    post :revoke, :token => "TOKEN STRING"
+  end
+  
+  def test_should_redirect_to_index
+    do_post
+    assert_response :redirect
+    assert_redirected_to('http://test.host/oauth_clients')
+  end
+  
+  def test_should_query_current_users_tokens
+    @tokens.expects(:find_by_token).returns(@request_token)
+    do_post
+  end
+  
+  def test_should_call_invalidate_on_token
+    @request_token.expects(:invalidate!)
+    do_post
+  end
+  
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_test_helper.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/controller_test_helper.rb
new file mode 100644 (file)
index 0000000..2827252
--- /dev/null
@@ -0,0 +1,115 @@
+require "mocha"
+module OAuthControllerTestHelper
+  
+  # Some custom stuff since we're using Mocha
+  def mock_model(model_class, options_and_stubs = {})
+    id = rand(10000)
+    options_and_stubs.reverse_merge! :id => id,
+      :to_param => id.to_s,
+      :new_record? => false,
+      :errors => stub("errors", :count => 0)
+      
+    m = stub("#{model_class.name}_#{options_and_stubs[:id]}", options_and_stubs)
+    m.instance_eval <<-CODE
+      def is_a?(other)
+        #{model_class}.ancestors.include?(other)
+      end
+      def kind_of?(other)
+        #{model_class}.ancestors.include?(other)
+      end
+      def instance_of?(other)
+        other == #{model_class}
+      end
+      def class
+        #{model_class}
+      end
+    CODE
+    yield m if block_given?
+    m
+  end
+    
+  def mock_full_client_application
+    mock_model(ClientApplication, 
+                :name => "App1", 
+                :url => "http://app.com", 
+                :callback_url => "http://app.com/callback",
+                :support_url => "http://app.com/support",
+                :key => "asd23423yy",
+                :secret => "secret",
+                :oauth_server => OAuth::Server.new("http://kowabunga.com")
+              )
+  end
+  
+  def login
+    @controller.stubs(:local_request?).returns(true)
+    @user = mock_model(User, :login => "ron")
+    @controller.stubs(:current_user).returns(@user)
+    @tokens=[]
+    @tokens.stubs(:find).returns(@tokens)
+    @user.stubs(:tokens).returns(@tokens)
+    User.stubs(:find_by_id).returns(@user)
+  end
+  
+  def login_as_application_owner
+    login
+    @client_application = mock_full_client_application
+    @client_applications = [@client_application]
+    
+    @user.stubs(:client_applications).returns(@client_applications)
+    @client_applications.stubs(:find).returns(@client_application)
+  end
+  
+  def setup_oauth
+    @controller.stubs(:local_request?).returns(true)
+    @user||=mock_model(User)
+    
+    User.stubs(:find_by_id).returns(@user)
+    
+    @server=OAuth::Server.new "http://test.host"
+    @consumer=OAuth::Consumer.new('key','secret',{:site=>"http://test.host"})
+
+    @client_application = mock_full_client_application
+    @controller.stubs(:current_client_application).returns(@client_application)
+    ClientApplication.stubs(:find_by_key).returns(@client_application)
+    @client_application.stubs(:key).returns(@consumer.key)
+    @client_application.stubs(:secret).returns(@consumer.secret)
+    @client_application.stubs(:name).returns("Client Application name")
+    @client_application.stubs(:callback_url).returns("http://application/callback")
+    @request_token=mock_model(RequestToken,:token=>'request_token',:client_application=>@client_application,:secret=>"request_secret",:user=>@user)
+    @request_token.stubs(:invalidated?).returns(false)
+    ClientApplication.stubs(:find_token).returns(@request_token)
+    
+    @request_token_string="oauth_token=request_token&oauth_token_secret=request_secret"
+    @request_token.stubs(:to_query).returns(@request_token_string)
+
+    @access_token=mock_model(AccessToken,:token=>'access_token',:client_application=>@client_application,:secret=>"access_secret",:user=>@user)
+    @access_token.stubs(:invalidated?).returns(false)
+    @access_token.stubs(:authorized?).returns(true)
+    @access_token_string="oauth_token=access_token&oauth_token_secret=access_secret"
+    @access_token.stubs(:to_query).returns(@access_token_string)
+
+    @client_application.stubs(:authorize_request?).returns(true)
+#    @client_application.stubs(:sign_request_with_oauth_token).returns(@request_token)
+    @client_application.stubs(:exchange_for_access_token).returns(@access_token)
+  end
+  
+  def setup_oauth_for_user
+    login
+    setup_oauth
+    @tokens=[@request_token]
+    @tokens.stubs(:find).returns(@tokens)
+    @tokens.stubs(:find_by_token).returns(@request_token)
+    @user.stubs(:tokens).returns(@tokens)
+  end
+  
+  def sign_request_with_oauth(token=nil)
+    ActionController::TestRequest.use_oauth=true
+    @request.configure_oauth(@consumer, token)
+  end
+    
+  def setup_to_authorize_request
+    setup_oauth
+    OauthToken.stubs(:find_by_token).with( @access_token.token).returns(@access_token)
+    @access_token.stubs(:is_a?).returns(true)
+  end
+end
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/edit.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/edit.html.erb
new file mode 100644 (file)
index 0000000..6c4f5ce
--- /dev/null
@@ -0,0 +1,5 @@
+<h1>Edit your application</h1>
+<%% form_for :client_application do |f| %>
+       <%%= render :partial => "form", :locals => { :f => f } %>
+       <%%= submit_tag "Edit" %>
+<%% end %>
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/helper.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/helper.rb
new file mode 100644 (file)
index 0000000..010cf9f
--- /dev/null
@@ -0,0 +1,2 @@
+module OauthHelper
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/index.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/index.html.erb
new file mode 100644 (file)
index 0000000..fcb3a03
--- /dev/null
@@ -0,0 +1,40 @@
+<div class="flash"><%%= flash[:notice] %></div>
+<h1>OAuth Client Applications</h1>
+<%% unless @tokens.empty? %>
+<p>The following tokens have been issued to applications in your name</p>
+<table>
+       <tr><th>Application</th><th>Issued</th><th>&nbsp;</th></tr>
+       <%% @tokens.each do |token|%>
+               <%% content_tag_for :tr, token do %>
+                       <td><%%= link_to token.client_application.name, token.client_application.url %></td>
+                       <td><%%= token.authorized_at %></td>
+                       <td>
+                               <%% form_tag :controller => 'oauth', :action => 'revoke' do %>
+                               <%%= hidden_field_tag 'token', token.token %>
+                               <%%= submit_tag "Revoke!" %>
+                               <%% end %>
+                       </td>
+               <%% end %>
+       <%% end %>
+       
+</table>
+<%% end %>
+<h3>Application Developers</h3>
+<%% if @client_applications.empty? %>
+       <p>
+               Do you have an application you would like to register for use with us using the <a href="http://oauth.net">OAuth</a> standard?
+       </p>
+       <p>
+               You must register your web application before it can make OAuth requests to this service
+       </p>
+<%% else %>
+       <p>
+               You have the following client applications registered:
+       </p>
+       <%% @client_applications.each do |client|%>
+               <%% div_for client do %>
+                       <%%= link_to client.name, :action => :show, :id => client.id %>
+               <%% end %>
+       <%% end %>
+<%% end %>
+<h3><%%= link_to "Register your application", :action => :new %></h3>
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/migration.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/migration.rb
new file mode 100644 (file)
index 0000000..c1b6b02
--- /dev/null
@@ -0,0 +1,44 @@
+class CreateOauthTables < ActiveRecord::Migration
+  def self.up
+    create_table :client_applications do |t|
+      t.string :name
+      t.string :url
+      t.string :support_url
+      t.string :callback_url
+      t.string :key, :limit => 50
+      t.string :secret, :limit => 50
+      t.integer :user_id
+
+      t.timestamps
+    end
+    add_index :client_applications, :key, :unique
+    
+    create_table :oauth_tokens do |t|
+      t.integer :user_id
+      t.string :type, :limit => 20
+      t.integer :client_application_id
+      t.string :token, :limit => 50
+      t.string :secret, :limit => 50
+      t.timestamp :authorized_at, :invalidated_at
+      t.timestamps
+    end
+    
+    add_index :oauth_tokens, :token, :unique
+    
+    create_table :oauth_nonces do |t|
+      t.string :nonce
+      t.integer :timestamp
+
+      t.timestamps
+    end
+    add_index :oauth_nonces,[:nonce, :timestamp], :unique
+    
+  end
+
+  def self.down
+    drop_table :client_applications
+    drop_table :oauth_tokens
+    drop_table :oauth_nonces
+  end
+
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/new.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/new.html.erb
new file mode 100644 (file)
index 0000000..be541da
--- /dev/null
@@ -0,0 +1,5 @@
+<h1>Register a new application</h1>
+<%% form_for :client_application, :url => { :action => :create } do |f| %>
+   <%%= render :partial => "form", :locals => { :f => f } %>
+   <%%= submit_tag "Register" %>
+<%% end %>
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce.rb
new file mode 100644 (file)
index 0000000..075351b
--- /dev/null
@@ -0,0 +1,13 @@
+# Simple store of nonces. The OAuth Spec requires that any given pair of nonce and timestamps are unique.
+# Thus you can use the same nonce with a different timestamp and viceversa.
+class OauthNonce < ActiveRecord::Base
+  validates_presence_of :nonce, :timestamp
+  validates_uniqueness_of :nonce, :scope => :timestamp
+  
+  # Remembers a nonce and it's associated timestamp. It returns false if it has already been used
+  def self.remember(nonce, timestamp)
+    oauth_nonce = OauthNonce.create(:nonce => nonce, :timestamp => timestamp)
+    return false if oauth_nonce.new_record?
+    oauth_nonce
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce_spec.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce_spec.rb
new file mode 100644 (file)
index 0000000..7829bdc
--- /dev/null
@@ -0,0 +1,24 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'oauth/helper'
+describe OauthNonce do
+  include OAuth::Helper
+  before(:each) do
+    @oauth_nonce = OauthNonce.remember(generate_key, Time.now.to_i)
+  end
+
+  it "should be valid" do
+    @oauth_nonce.should be_valid
+  end
+  
+  it "should not have errors" do
+    @oauth_nonce.errors.full_messages.should == []
+  end
+  
+  it "should not be a new record" do
+    @oauth_nonce.should_not be_new_record
+  end
+  
+  it "should not allow a second one with the same values" do
+    OauthNonce.remember(@oauth_nonce.nonce,@oauth_nonce.timestamp).should == false
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce_test.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonce_test.rb
new file mode 100644 (file)
index 0000000..2fd6a75
--- /dev/null
@@ -0,0 +1,26 @@
+require 'oauth/helper'
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ClientNoneTest < ActiveSupport::TestCase
+  include OAuth::Helper
+  
+  def setup
+    @oauth_nonce = OauthNonce.remember(generate_key,Time.now.to_i)
+  end
+
+  def test_should_be_valid
+    assert @oauth_nonce.valid?
+  end
+  
+  def test_should_not_have_errors
+    assert_equal [], @oauth_nonce.errors.full_messages
+  end
+  
+  def test_should_not_be_a_new_record
+    assert !@oauth_nonce.new_record?
+  end
+  
+  def test_shuold_not_allow_a_second_one_with_the_same_values
+    assert_equal false, OauthNonce.remember(@oauth_nonce.nonce, @oauth_nonce.timestamp)
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonces.yml b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_nonces.yml
new file mode 100644 (file)
index 0000000..4e0b306
--- /dev/null
@@ -0,0 +1,13 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+one:
+  id: 1
+  nonce: a_nonce
+  timestamp: 1
+  created_at: 2007-11-25 17:27:04
+  updated_at: 2007-11-25 17:27:04
+two:
+  id: 2
+  nonce: b_nonce
+  timestamp: 2
+  created_at: 2007-11-25 17:27:04
+  updated_at: 2007-11-25 17:27:04
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token.rb
new file mode 100644 (file)
index 0000000..5fca40c
--- /dev/null
@@ -0,0 +1,31 @@
+class OauthToken < ActiveRecord::Base
+  belongs_to :client_application
+  belongs_to :user
+  validates_uniqueness_of :token
+  validates_presence_of :client_application, :token, :secret
+  before_validation_on_create :generate_keys
+  
+  def invalidated?
+    invalidated_at != nil
+  end
+  
+  def invalidate!
+    update_attribute(:invalidated_at, Time.now)
+  end
+  
+  def authorized?
+    authorized_at != nil && !invalidated?
+  end
+  
+  def to_query
+    "oauth_token=#{token}&oauth_token_secret=#{secret}"
+  end
+    
+protected
+  
+  def generate_keys
+    @oauth_token = client_application.oauth_server.generate_credentials
+    self.token = @oauth_token[0]
+    self.secret = @oauth_token[1]
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token_spec.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token_spec.rb
new file mode 100644 (file)
index 0000000..594c204
--- /dev/null
@@ -0,0 +1,55 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe RequestToken do
+  fixtures :client_applications, :users, :oauth_tokens
+  before(:each) do
+    @token = RequestToken.create :client_application => client_applications(:one)
+  end
+
+  it "should be valid" do
+    @token.should be_valid
+  end
+  
+  it "should not have errors" do
+    @token.errors.should_not == []
+  end
+  
+  it "should have a token" do
+    @token.token.should_not be_nil
+  end
+
+  it "should have a secret" do
+    @token.secret.should_not be_nil
+  end
+  
+  it "should not be authorized" do 
+    @token.should_not be_authorized
+  end
+
+  it "should not be invalidated" do
+    @token.should_not be_invalidated
+  end
+  
+  it "should authorize request" do
+    @token.authorize!(users(:quentin))
+    @token.should be_authorized
+    @token.authorized_at.should_not be_nil
+    @token.user.should == users(:quentin)
+  end
+  
+  it "should not exchange without approval" do
+    @token.exchange!.should == false
+    @token.should_not be_invalidated
+  end
+  
+  it "should not exchange without approval" do
+    @token.authorize!(users(:quentin))
+    @access = @token.exchange!
+    @access.should_not == false
+    @token.should be_invalidated
+    
+    @access.user.should == users(:quentin)
+    @access.should be_authorized
+  end
+  
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token_test.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_token_test.rb
new file mode 100644 (file)
index 0000000..dc7f5cb
--- /dev/null
@@ -0,0 +1,57 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class RequestTokenTest < ActiveSupport::TestCase
+
+  fixtures :client_applications, :users, :oauth_tokens
+  
+  def setup
+    @token = RequestToken.create :client_application=>client_applications(:one)
+  end
+
+  def test_should_be_valid
+    assert @token.valid?
+  end
+  
+  def test_should_not_have_errors
+    assert @token.errors.empty?
+  end
+  
+  def test_should_have_a_token
+    assert_not_nil @token.token
+  end
+
+  def test_should_have_a_secret
+    assert_not_nil @token.secret
+  end
+  
+  def test_should_not_be_authorized 
+    assert !@token.authorized?
+  end
+
+  def test_should_not_be_invalidated
+    assert !@token.invalidated?
+  end
+  
+  def test_should_authorize_request
+    @token.authorize!(users(:quentin))
+    assert @token.authorized?
+    assert_not_nil @token.authorized_at
+    assert_equal users(:quentin), @token.user
+  end
+  
+  def test_should_not_exchange_without_approval
+    assert_equal false, @token.exchange!
+    assert_equal false, @token.invalidated?
+  end
+  
+  def test_should_not_exchange_without_approval
+    @token.authorize!(users(:quentin))
+    @access = @token.exchange!
+    assert_not_equal false, @access
+    assert @token.invalidated?
+    
+    assert_equal users(:quentin), @access.user
+    assert @access.authorized?
+  end
+  
+end
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_tokens.yml b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/oauth_tokens.yml
new file mode 100644 (file)
index 0000000..1c8006e
--- /dev/null
@@ -0,0 +1,17 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+one:
+  id: 1
+  user_id: 1
+  client_application_id: 1
+  token: one
+  secret: MyString
+  created_at: 2007-11-19 07:31:46
+  updated_at: 2007-11-19 07:31:46
+two:
+  id: 2
+  user_id: 1
+  client_application_id: 1
+  token: two
+  secret: MyString
+  created_at: 2007-11-19 07:31:46
+  updated_at: 2007-11-19 07:31:46
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/request_token.rb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/request_token.rb
new file mode 100644 (file)
index 0000000..b6047fe
--- /dev/null
@@ -0,0 +1,17 @@
+class RequestToken < OauthToken
+  def authorize!(user)
+    return false if authorized?
+    self.user = user
+    self.authorized_at = Time.now
+    self.save
+  end
+  
+  def exchange!
+    return false unless authorized?
+    RequestToken.transaction do
+      access_token = AccessToken.create(:user => user, :client_application => client_application)
+      invalidate!
+      access_token
+    end
+  end
+end
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/show.html.erb b/vendor/plugins/oauth-plugin/generators/oauth_provider/templates/show.html.erb
new file mode 100644 (file)
index 0000000..a997e2f
--- /dev/null
@@ -0,0 +1,20 @@
+<h1>OAuth details for <%%=@client_application.name %></h1>
+<p>
+       <b>Consumer Key:</b> <%%=@client_application.key %>
+</p>
+<p>
+       <b>Consumer Secret:</b> <%%=@client_application.secret %>
+</p>
+<p>
+       <b>Request Token URL</b> http<%%='s' if request.ssl? %>://<%%= request.host_with_port %><%%=@client_application.oauth_server.request_token_path %>
+</p>
+<p>
+       <b>Access Token URL</b> http<%%='s' if request.ssl? %>://<%%= request.host_with_port %><%%=@client_application.oauth_server.access_token_path %>
+</p>
+<p>
+       <b>Authorize URL</b> http<%%='s' if request.ssl? %>://<%%= request.host_with_port %><%%=@client_application.oauth_server.authorize_path %>
+</p>
+
+<p>
+       We support hmac-sha1 (recommended) as well as plain text in ssl mode.
+</p>
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/init.rb b/vendor/plugins/oauth-plugin/init.rb
new file mode 100644 (file)
index 0000000..28e2556
--- /dev/null
@@ -0,0 +1,6 @@
+gem 'oauth', '>=0.2.1'
+require 'oauth/signature/hmac/sha1'
+require 'oauth/request_proxy/action_controller_request'
+require 'oauth/server'
+require 'oauth/rails/controller_methods'
+ActionController::Base.send :include, OAuth::Rails::ControllerMethods
diff --git a/vendor/plugins/oauth-plugin/install.rb b/vendor/plugins/oauth-plugin/install.rb
new file mode 100644 (file)
index 0000000..f1531bd
--- /dev/null
@@ -0,0 +1,2 @@
+#should we do any text formatting?
+puts IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))
\ No newline at end of file
diff --git a/vendor/plugins/oauth-plugin/lib/oauth/rails/controller_methods.rb b/vendor/plugins/oauth-plugin/lib/oauth/rails/controller_methods.rb
new file mode 100644 (file)
index 0000000..68ef9d2
--- /dev/null
@@ -0,0 +1,114 @@
+require 'oauth/signature'
+module OAuth
+  module Rails
+   
+    module ControllerMethods
+      protected
+      
+      def current_token
+        @current_token
+      end
+      
+      def current_client_application
+        @current_client_application
+      end
+      
+      def oauthenticate
+        logger.info "entering oauthenticate"
+        verified=verify_oauth_signature 
+        logger.info "verified=#{verified.to_s}"
+        return verified && current_token.is_a?(::AccessToken)
+      end
+      
+      def oauth?
+        current_token!=nil
+      end
+      
+      # use in a before_filter
+      def oauth_required
+        logger.info "Current_token=#{@current_token.inspect}"
+        if oauthenticate
+          logger.info "passed oauthenticate"
+          if authorized?
+            logger.info "passed authorized"
+            return true
+          else
+            logger.info "failed authorized"
+            invalid_oauth_response
+          end
+        else
+          logger.info "failed oauthenticate"
+          
+          invalid_oauth_response
+        end
+      end
+      
+      # This requies that you have an acts_as_authenticated compatible authentication plugin installed
+      def login_or_oauth_required
+        if oauthenticate
+          if authorized?
+            return true
+          else
+            invalid_oauth_response
+          end
+        else
+          login_required
+        end
+      end
+      
+      
+      # verifies a request token request
+      def verify_oauth_consumer_signature
+        begin
+          valid = ClientApplication.verify_request(request) do |token, consumer_key|
+            @current_client_application = ClientApplication.find_by_key(consumer_key)
+
+            # return the token secret and the consumer secret
+            [nil, @current_client_application.secret]
+          end
+        rescue
+          valid=false
+        end
+
+        invalid_oauth_response unless valid
+      end
+
+      def verify_oauth_request_token
+        verify_oauth_signature && current_token.is_a?(RequestToken)
+      end
+
+      def invalid_oauth_response(code=401,message="Invalid OAuth Request")
+        render :text => message, :status => code
+      end
+
+      private
+      
+      def current_token=(token)
+        @current_token=token
+        if @current_token
+          @current_user=@current_token.user
+          @current_client_application=@current_token.client_application 
+        end
+        @current_token
+      end
+      
+      # Implement this for your own application using app-specific models
+      def verify_oauth_signature
+        begin
+          valid = ClientApplication.verify_request(request) do |request|
+            self.current_token = OauthToken.find_token(request.token)
+            logger.info "self=#{self.class.to_s}"
+            logger.info "token=#{self.current_token}"
+            # return the token secret and the consumer secret
+            [(current_token.nil? ? nil : current_token.secret), (current_client_application.nil? ? nil : current_client_application.secret)]
+          end
+          # reset @current_user to clear state for restful_...._authentication
+          @current_user = nil if (!valid)
+          valid
+        rescue
+          false
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/plugins/oauth-plugin/tasks/oauth_tasks.rake b/vendor/plugins/oauth-plugin/tasks/oauth_tasks.rake
new file mode 100644 (file)
index 0000000..fd2b0e1
--- /dev/null
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :oauth do
+#   # Task goes here
+# end
diff --git a/vendor/plugins/oauth-plugin/uninstall.rb b/vendor/plugins/oauth-plugin/uninstall.rb
new file mode 100644 (file)
index 0000000..9738333
--- /dev/null
@@ -0,0 +1 @@
+# Uninstall hook code here