mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-29 13:15:34 +08:00
Remove remaining OAuth test stuff
This commit is contained in:
@@ -1,2 +1 @@
|
||||
require 'restkit/network/authentication'
|
||||
require 'restkit/network/oauth2'
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
require 'rack/auth/abstract/request'
|
||||
require 'simple_oauth'
|
||||
require 'ruby_debug'
|
||||
|
||||
TOKEN_SECRET = 'monkey'
|
||||
CLIENT_SECRET = 'restkit_secret'
|
||||
|
||||
module RestKit
|
||||
module Network
|
||||
module OAuth1
|
||||
class Middleware
|
||||
|
||||
# This class modified from https://github.com/tonywok/forcefield
|
||||
|
||||
# Copyright (c) 2011 EdgeCase, Tony Schneider
|
||||
#
|
||||
# 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.
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
# rebuild the original path so that signatures match
|
||||
env.delete 'SCRIPT_NAME'
|
||||
env['PATH_INFO'] = '/oauth1' + env['PATH_INFO']
|
||||
|
||||
@request = RestKit::Network::OAuth1::Request.new(env)
|
||||
|
||||
@request.with_valid_request do
|
||||
if client_verified?
|
||||
@app.call(env)
|
||||
else
|
||||
[401, {}, ["Unauthorized."]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def client_verified?
|
||||
@request.verify_signature("restkit_secret")
|
||||
end
|
||||
end
|
||||
|
||||
class Request < Rack::Auth::AbstractRequest
|
||||
|
||||
# This class modified from https://github.com/tonywok/forcefield
|
||||
|
||||
# Copyright (c) 2011 EdgeCase, Tony Schneider
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
# This method encapsulates the various checks we need to make against the request's
|
||||
# Authorization header before we deem it ready for verification.
|
||||
# Upon passing the checks, we yield to the block so that simple_oauth can determine
|
||||
# whether or not the request has been properly signed.
|
||||
#
|
||||
def with_valid_request
|
||||
if provided? # #provided? defined in Rack::Auth::AbstractRequest
|
||||
if !oauth?
|
||||
[400, {}, ["Bad request. No auth scheme provided."]]
|
||||
elsif params[:consumer_key].nil?
|
||||
[400, {}, ["Bad request. No consumer key provided."]]
|
||||
elsif params[:signature].nil?
|
||||
[400, {}, ["Bad request. No signature provided."]]
|
||||
elsif params[:signature_method].nil?
|
||||
[400, {}, ["Bad request. No signature method provided."]]
|
||||
else
|
||||
yield(request.env)
|
||||
end
|
||||
else
|
||||
[400, {}, ["Bad request."]]
|
||||
end
|
||||
end
|
||||
|
||||
def verify_signature(client_secret)
|
||||
return false unless client_secret
|
||||
header = SimpleOAuth::Header.new(request.request_method, request.url, included_request_params, auth_header)
|
||||
|
||||
header.valid?({:consumer_secret => CLIENT_SECRET, :token_secret => TOKEN_SECRET})
|
||||
end
|
||||
|
||||
def consumer_key
|
||||
params[:consumer_key]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def params
|
||||
@params ||= SimpleOAuth::Header.parse(auth_header)
|
||||
end
|
||||
|
||||
# #scheme is defined as an instance method on Rack::Auth::AbstractRequest
|
||||
#
|
||||
def oauth?
|
||||
scheme == :oauth
|
||||
end
|
||||
|
||||
def auth_header
|
||||
@env[authorization_key]
|
||||
end
|
||||
|
||||
# only include request params if Content-Type is set to application/x-www/form-urlencoded
|
||||
# (see http://tools.ietf.org/html/rfc5849#section-3.4.1)
|
||||
#
|
||||
def included_request_params
|
||||
request.content_type == "application/x-www-form-urlencoded" ? request.params : nil
|
||||
end
|
||||
end
|
||||
|
||||
class App < Sinatra::Base
|
||||
configure do
|
||||
enable :logging, :dump_errors
|
||||
end
|
||||
|
||||
get '/oauth1/me' do
|
||||
response = {'user_id' => 1, 'name' => 'Rod'}
|
||||
content_type 'application/json'
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,150 +0,0 @@
|
||||
require "rack/oauth2/sinatra"
|
||||
require "rack/oauth2/server"
|
||||
|
||||
# Override this so we can specify an ObjectId manually
|
||||
module Rack
|
||||
module OAuth2
|
||||
class Server
|
||||
class AuthRequest
|
||||
class << self
|
||||
def create(client, scope, redirect_uri, response_type, state, id = nil)
|
||||
scope = Utils.normalize_scope(scope) & client.scope # Only allowed scope
|
||||
fields = { :client_id=>client.id, :scope=>scope, :redirect_uri=>client.redirect_uri || redirect_uri,
|
||||
:response_type=>response_type, :state=>state,
|
||||
:grant_code=>nil, :authorized_at=>nil,
|
||||
:created_at=>Time.now.to_i, :revoked=>nil }
|
||||
fields[:_id] = BSON::ObjectId.from_string(id) if id
|
||||
fields[:_id] = collection.insert(fields)
|
||||
Server.new_instance self, fields
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module RestKit
|
||||
module Network
|
||||
module OAuth2
|
||||
module Scenarios
|
||||
class App
|
||||
def initialize(app)
|
||||
@base_url = '/oauth2/basic'
|
||||
end
|
||||
|
||||
def db_setup
|
||||
Rack::OAuth2::Server.options.database = Mongo::Connection.new[ENV["DB"]]
|
||||
Rack::OAuth2::Server.options.collection_prefix = "oauth2_prefix"
|
||||
end
|
||||
|
||||
def setup(env)
|
||||
Rack::OAuth2::Server.options.authorize_path = "/authorize"
|
||||
Rack::OAuth2::Server.options.access_token_path = "/token"
|
||||
Rack::OAuth2::Server.options.authorization_types = ["code", "token"]
|
||||
create_fixtures
|
||||
end
|
||||
|
||||
def create_fixtures
|
||||
@client = Rack::OAuth2::Server.register(RESTKIT_CLIENT_PARAMS)
|
||||
end
|
||||
|
||||
def teardown(response)
|
||||
if redirect?(response)
|
||||
response[1]["Location"].gsub!(/\/authorize/, @base_url + '/authorize')
|
||||
response[1]["Location"].gsub!(/\/token/, @base_url + '/token')
|
||||
response[1]["Location"].gsub!(/\/me/, @base_url + '/me')
|
||||
end
|
||||
end
|
||||
|
||||
def redirect?(response)
|
||||
response && response[1] && response[1]["Location"]
|
||||
end
|
||||
|
||||
def drop_all
|
||||
Rack::OAuth2::Server::Client.collection.drop
|
||||
Rack::OAuth2::Server::AuthRequest.collection.drop
|
||||
Rack::OAuth2::Server::AccessGrant.collection.drop
|
||||
Rack::OAuth2::Server::AccessToken.collection.drop
|
||||
Rack::OAuth2::Server::Issuer.collection.drop
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env.delete 'SCRIPT_NAME' # otherwise Rack::OAuth::Server will merge this back into path_info
|
||||
db_setup
|
||||
|
||||
if env['PATH_INFO'] =~ /^\/reset/
|
||||
drop_all
|
||||
[200, {}, "Aye, aye!"]
|
||||
else
|
||||
setup env
|
||||
response = OAuth2App.call(env)
|
||||
teardown response
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
def create_access_grant(identity, client, scope, id = nil, redirect_uri = nil, expires = nil)
|
||||
raise ArgumentError, "Identity must be String or Integer" unless String === identity || Integer === identity
|
||||
scope = Rack::OAuth2::Server::Utils.normalize_scope(scope) & client.scope # Only allowed scope
|
||||
expires_at = Time.now.to_i + (expires || 300)
|
||||
id = Rack::OAuth2::Server.secure_random unless id
|
||||
fields = { :_id=>id, :identity=>identity, :scope=>scope,
|
||||
:client_id=>client.id, :redirect_uri=>client.redirect_uri || redirect_uri,
|
||||
:created_at=>Time.now.to_i, :expires_at=>expires_at, :granted_at=>nil,
|
||||
:access_token=>nil, :revoked=>nil }
|
||||
Rack::OAuth2::Server::AccessGrant.collection.insert fields
|
||||
Rack::OAuth2::Server.new_instance Rack::OAuth2::Server::AccessGrant, fields
|
||||
end
|
||||
end
|
||||
|
||||
class PregeneratedTokens < App
|
||||
def initialize(app)
|
||||
@base_url = '/oauth2/pregen'
|
||||
end
|
||||
|
||||
def setup(env)
|
||||
drop_all
|
||||
super
|
||||
end
|
||||
|
||||
def create_fixtures
|
||||
@client = Rack::OAuth2::Server.register(RESTKIT_CLIENT_PARAMS)
|
||||
@auth_request = Rack::OAuth2::Server::AuthRequest.find('4fa8182d7184797dd5000001') || Rack::OAuth2::Server::AuthRequest.create(@client, @client.scope, @client.redirect_uri.to_s, 'code', nil, '4fa8182d7184797dd5000001')
|
||||
@access_grant = create_access_grant("Identity", @client, @client.scope, '4fa8182d7184797dd5000002', @client.redirect_uri)
|
||||
|
||||
@auth_request.grant_code = @access_grant.code
|
||||
Rack::OAuth2::Server::AuthRequest.collection.update({:_id=>@auth_request.id, :revoked=>nil}, {:$set=>{ :grant_code=>@access_grant.code, :authorized_at=> Time.now}})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class OAuth2App < Sinatra::Base
|
||||
register Rack::OAuth2::Sinatra
|
||||
|
||||
configure do
|
||||
enable :logging, :dump_errors
|
||||
end
|
||||
|
||||
set :sessions, true
|
||||
set :show_exceptions, false
|
||||
|
||||
get "/authorize" do
|
||||
if oauth.client
|
||||
"client: #{oauth.client.display_name}\nscope: #{oauth.scope.join(", ")}\nauthorization: #{oauth.authorization}"
|
||||
else
|
||||
"No client"
|
||||
end
|
||||
end
|
||||
|
||||
oauth_required "/me"
|
||||
|
||||
get '/me' do
|
||||
response = {'user_id' => 1, 'name' => 'Rod'}
|
||||
content_type 'application/json'
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,16 +12,12 @@ rescue LoadError
|
||||
# No debugging...
|
||||
end
|
||||
|
||||
ENV["DB"] = "rack_oauth2_server"
|
||||
|
||||
# Import the RestKit Test server
|
||||
$: << File.join(File.expand_path(File.dirname(__FILE__)), 'lib')
|
||||
require File.expand_path(File.dirname(__FILE__)) + '/fixtures'
|
||||
require 'restkit/network/authentication'
|
||||
require 'restkit/network/etags'
|
||||
require 'restkit/network/timeout'
|
||||
require 'restkit/network/oauth1'
|
||||
require 'restkit/network/oauth2'
|
||||
require 'restkit/network/redirection'
|
||||
|
||||
class Person < Struct.new(:name, :age)
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
require File.expand_path(File.dirname(__FILE__)) + '/server'
|
||||
|
||||
# Basic OAuth 2.0 implementation
|
||||
map '/oauth2/basic' do
|
||||
run RestKit::Network::OAuth2::Scenarios::App.new(nil)
|
||||
end
|
||||
|
||||
map '/oauth2/pregen' do
|
||||
run RestKit::Network::OAuth2::Scenarios::PregeneratedTokens.new(nil)
|
||||
end
|
||||
|
||||
# Should just be /reset
|
||||
map '/oauth2reset' do
|
||||
run RestKit::Network::OAuth2::Scenarios::App.new(nil)
|
||||
end
|
||||
|
||||
map '/oauth1' do
|
||||
use RestKit::Network::OAuth1::Middleware
|
||||
run RestKit::Network::OAuth1::App
|
||||
end
|
||||
|
||||
map '/' do
|
||||
run RestKitTestServer
|
||||
end
|
||||
@@ -1,75 +0,0 @@
|
||||
require File.dirname(__FILE__) + "/spec_helper"
|
||||
require 'simple_oauth'
|
||||
|
||||
describe "OAuth1" do
|
||||
def app
|
||||
Rack::Builder.parse_file(File.dirname(__FILE__) + "/../server.ru").first
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
@oauth = {
|
||||
:token => "12345",
|
||||
:consumer_key => "restkit",
|
||||
:consumer_secret => "restkit_secret",
|
||||
:token_secret => "monkey"
|
||||
}
|
||||
end
|
||||
|
||||
def header_without(key = nil)
|
||||
oauth_header = SimpleOAuth::Header.new(:get, "http://example.org/oauth1/me", nil, @oauth)
|
||||
attributes = oauth_header.signed_attributes.clone
|
||||
attributes.delete key if key
|
||||
"OAuth " + attributes.sort_by{|k,v| k.to_s }.map{|k,v| %(#{k}="#{SimpleOAuth::Header.encode(v)}") }.join(', ')
|
||||
end
|
||||
|
||||
context "Dispatching a valid OAuth1.0a header" do
|
||||
it "should succeed" do
|
||||
header 'Authorization', header_without(nil)
|
||||
get "/oauth1/me"
|
||||
|
||||
last_response.should be_successful
|
||||
end
|
||||
end
|
||||
|
||||
context "Dispatching an invalid OAuth1.0a header" do
|
||||
context "without a consumer key" do
|
||||
it "should fail" do
|
||||
header 'Authorization', header_without(:oauth_consumer_key)
|
||||
get "/oauth1/me"
|
||||
|
||||
last_response.status.should eq 400
|
||||
last_response.body.should eq "Bad request. No consumer key provided."
|
||||
end
|
||||
end
|
||||
|
||||
context "without a signature" do
|
||||
it "should fail" do
|
||||
header 'Authorization', header_without(:oauth_signature)
|
||||
get "/oauth1/me"
|
||||
|
||||
last_response.status.should eq 400
|
||||
last_response.body.should eq "Bad request. No signature provided."
|
||||
end
|
||||
end
|
||||
|
||||
context "without a signature method" do
|
||||
it "should fail" do
|
||||
header 'Authorization', header_without(:oauth_signature_method)
|
||||
get "/oauth1/me"
|
||||
|
||||
last_response.status.should eq 400
|
||||
last_response.body.should eq "Bad request. No signature method provided."
|
||||
end
|
||||
end
|
||||
|
||||
context "without a header at all" do
|
||||
it "should fail" do
|
||||
get "/oauth1/me"
|
||||
|
||||
last_response.status.should eq 400
|
||||
last_response.body.should eq "Bad request."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,95 +0,0 @@
|
||||
require File.dirname(__FILE__) + "/spec_helper"
|
||||
|
||||
describe "OAuth2" do
|
||||
def app
|
||||
Rack::Builder.parse_file(File.dirname(__FILE__) + "/../server.ru").first
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
clear_database
|
||||
@client = Server.register(RESTKIT_CLIENT_PARAMS)
|
||||
@params = {:redirect_uri=>'http://restkit.org/', :client_id=>@client.id, :client_secret=>@client.secret, :response_type=>"code", :scope=>"read write", :state=>"bring this back" }
|
||||
end
|
||||
|
||||
def clear_database
|
||||
Rack::OAuth2::Server::Client.collection.drop
|
||||
Rack::OAuth2::Server::AuthRequest.collection.drop
|
||||
Rack::OAuth2::Server::AccessGrant.collection.drop
|
||||
Rack::OAuth2::Server::AccessToken.collection.drop
|
||||
Rack::OAuth2::Server::Issuer.collection.drop
|
||||
end
|
||||
|
||||
context "Resetting the OAuth2 pathway" do
|
||||
it "should clear the database" do
|
||||
clear_database
|
||||
Rack::OAuth2::Server::Client.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::AuthRequest.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::AccessGrant.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::AccessToken.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::Issuer.collection.count.should eq 0
|
||||
|
||||
Rack::OAuth2::Server.register(RESTKIT_CLIENT_PARAMS)
|
||||
Rack::OAuth2::Server::Client.collection.count.should eq 1
|
||||
|
||||
get "/oauth2/basic/authorize?" + Rack::Utils.build_query(@params)
|
||||
get last_response["Location"] if last_response.status == 303
|
||||
|
||||
Rack::OAuth2::Server::AuthRequest.collection.count.should eq 1
|
||||
|
||||
get "/oauth2reset/reset"
|
||||
|
||||
Rack::OAuth2::Server::Client.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::AuthRequest.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::AccessGrant.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::AccessToken.collection.count.should eq 0
|
||||
Rack::OAuth2::Server::Issuer.collection.count.should eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context "Given a basic OAuth2 setup" do
|
||||
context "Requesting the authorization URL" do
|
||||
|
||||
context "With valid params" do
|
||||
it "Should report the client" do
|
||||
get "/oauth2/basic/authorize?" + Rack::Utils.build_query(@params)
|
||||
get last_response["Location"] if last_response.status == 303
|
||||
|
||||
response = last_response.body.split("\n").inject({}) { |h,l| n,v = l.split(/:\s*/) ; h[n.downcase] = v ; h }
|
||||
response["client"].should eq @client.display_name
|
||||
end
|
||||
end
|
||||
|
||||
context "Without valid params" do
|
||||
it "Should fail" do
|
||||
get "/oauth2/basic/authorize"
|
||||
last_response.should_not be_successful
|
||||
last_response.should_not be_redirect
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "And a pre-generated authorization token and access grant" do
|
||||
context "Requesting the authorization URL with the token" do
|
||||
it "should report the client" do
|
||||
get "/oauth2/pregen/authorize?" + Rack::Utils.build_query({:authorization => '4fa8182d7184797dd5000001'})
|
||||
response = last_response.body.split("\n").inject({}) { |h,l| n,v = l.split(/:\s*/) ; h[n.downcase] = v ; h }
|
||||
response["client"].should eq @client.display_name
|
||||
end
|
||||
end
|
||||
|
||||
context "Requesting the token URL with the access grant token" do
|
||||
it "should return a token" do
|
||||
params = {
|
||||
:code => '4fa8182d7184797dd5000002',
|
||||
:client_id => @client.id,
|
||||
:client_secret => @client.secret,
|
||||
:redirect_uri => @client.redirect_uri,
|
||||
:grant_type => 'authorization_code'
|
||||
}
|
||||
post "/oauth2/pregen/token", params
|
||||
JSON.parse(last_response.body)["access_token"].should_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,14 +0,0 @@
|
||||
require File.dirname(__FILE__) + "/../server"
|
||||
require File.expand_path(File.dirname(__FILE__)) + '/../fixtures'
|
||||
require "rubygems"
|
||||
require "test/unit"
|
||||
require "rack/test"
|
||||
require "rack/oauth2/server"
|
||||
|
||||
Rack::OAuth2::Server.options.database = Mongo::Connection.new[ENV["DB"]]
|
||||
Rack::OAuth2::Server.options.collection_prefix = "oauth2_prefix"
|
||||
|
||||
RSpec.configure do |conf|
|
||||
conf.include Rack::Test::Methods
|
||||
conf.include Rack::OAuth2
|
||||
end
|
||||
Reference in New Issue
Block a user