diff --git a/.gitignore b/.gitignore index 5fff1d9..9a1433f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ pkg +.bundle +vendor/bundle diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..34d47bd --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source "http://rubygems.org" + +gem "rspec" +gem "ruby-debug" +gem "activesupport" +gem "rake" +gem "hoe" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..5de6c3d --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,29 @@ +GEM + remote: http://rubygems.org/ + specs: + activesupport (3.0.0) + columnize (0.3.1) + hoe (2.6.2) + rake (>= 0.8.7) + rubyforge (>= 2.0.4) + json_pure (1.4.6) + linecache (0.43) + rake (0.8.7) + rspec (1.3.0) + ruby-debug (0.10.3) + columnize (>= 0.1) + ruby-debug-base (~> 0.10.3.0) + ruby-debug-base (0.10.3) + linecache (>= 0.3) + rubyforge (2.0.4) + json_pure (>= 1.1.7) + +PLATFORMS + ruby + +DEPENDENCIES + activesupport + hoe + rake + rspec + ruby-debug diff --git a/README.rdoc b/README.rdoc index ce31a29..4c44cd1 100644 --- a/README.rdoc +++ b/README.rdoc @@ -4,6 +4,9 @@ auth-hmac is a Ruby implementation of HMAC[http://en.wikipedia.org/wiki/HMAC] based authentication of HTTP requests. +This is the DNC Innovation Lab fork of the project. We added Rack support and some other more obscure stuff for HMAC proxying that you probably won't need unless you're doing something weird like we are. :) +Github user rjackson contributed Ruby 1.9 support, which is pretty awesome. + HMAC authentication involves a client and server having a shared secret key. When sending the request the client, signs the request using the secret key. This involves building a canonical representation of the request and then generating a HMAC of the request using the secret. The generated HMAC is then sent as part of the request. When the server receives the request it builds the same canonical representation and generates a HMAC using it's copy of the secret key, if the HMAC produced by the server matches the HMAC sent by the client, the server can be assured that the client also possesses the shared secret key. @@ -33,7 +36,7 @@ AuthHMAC.sign! takes a HTTP request object, an access id and a secret key and si * The secret key is the shared secret between the client and the server. You should make this sufficiently random so that is can't be guessed or exposed to dictionary attacks. The follow code will give you a pretty good secret key: random = File.read('/dev/random', 512) - secret_key = Base64.encode64(Digest::SHA2.new(512).digest(random)) + secret_key = [Digest::SHA2.new(512).digest(random)].pack('m') On the server side you can then authenticate these requests using the AuthHMAC.authenticated? method. This takes the same arguments as the sign! method but returns true if the request has been signed with the access id and secret or false if it hasn't. @@ -51,10 +54,6 @@ will sign +request+ with "access_id1" and it's corresponding secret key. Simila which will return true if the request has been signed with one of the access id and secret key pairs provided in the constructor. -=== Rails Integration - -AuthHMAC supports authentication within Rails controllers and signing of requests generated by Active Resource. See AuthHMAC::Rails::ControllerFilter::ClassMethods and AuthHMAC::Rails::ActiveResourceExtension::BaseHmac::ClassMethods for details. - == How does it work? When creating a signature for a HTTP request AuthHMAC first generates a canonical representation of the request. @@ -83,25 +82,23 @@ Using these details it is possible to build code that will sign and authenticate == INSTALL: -* sudo gem install auth-hmac +* sudo gem install dnclabs-auth-hmac == Source Code -The source repository is accessible via GitHub or Ruby Forge: +The source repository is accessible via GitHub: - git clone git://github.com/seangeo/auth-hmac.git - - - git clone git://rubyforge.org/auth-hmac.git + git clone git://github.com/dnclabs/auth-hmac.git == Contact Information -The project page is at http://rubyforge.org/projects/auth-hmac. Please file any bugs or feedback -using the trackers and forums there. +Please file any bugs or feedback on http://github.com/dnclabs/auth-hmac/ == Authors and Contributors -rAtom was developed by Peerworks[http://peerworks.org] and written by Sean Geoghegan. +Upstream credits: rAtom was developed by Peerworks[http://peerworks.org] and written by Sean Geoghegan. + +This fork: Maintained by the Democratic National Committee Innovation Labs team. == LICENSE: @@ -126,4 +123,4 @@ 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. \ No newline at end of file +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Rakefile b/Rakefile index e469154..c6c7562 100644 --- a/Rakefile +++ b/Rakefile @@ -1,4 +1,9 @@ -require 'config/requirements' -require 'config/hoe' # setup Hoe + all gem configuration - -Dir['tasks/**/*.rake'].each { |rake| load rake } \ No newline at end of file +require 'config/requirements' +require 'config/hoe' # setup Hoe + all gem configuration + +require 'spec/rake/spectask' +desc "Run the specs under spec/models" +Spec::Rake::SpecTask.new do |t| + t.spec_opts = ['--options', "spec/spec.opts"] + t.spec_files = FileList['spec/**/*_spec.rb'] +end diff --git a/auth-hmac.gemspec b/auth-hmac.gemspec index bd9403c..d44d6c6 100644 --- a/auth-hmac.gemspec +++ b/auth-hmac.gemspec @@ -1,26 +1,18 @@ # -*- encoding: utf-8 -*- Gem::Specification.new do |s| - s.name = %q{auth-hmac} - s.version = "1.1.0" + s.name = %q{dnclabs-auth-hmac} + s.version = "1.1.1.2010090201" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Sean Geoghegan", "ascarter"] - s.date = %q{2009-02-26} - s.description = %q{A gem providing HMAC based authentication for HTTP} - s.email = %q{seangeo@gmail.com} + s.authors = ["Sean Geoghegan", "ascarter", "Wes Morgan", "Adrian Cushman"] + s.date = %q{2010-09-02} + s.description = %q{A gem providing HMAC based authentication for HTTP. This is the DNC Labs fork.} + s.email = %q{innovationlab@dnc.org} s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.txt"] s.files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.txt", "Rakefile", "config/hoe.rb", "config/requirements.rb", "lib/auth-hmac.rb", "lib/auth-hmac/version.rb", "script/console", "script/destroy", "script/generate", "setup.rb", "spec/auth-hmac_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/deployment.rake", "tasks/environment.rake", "tasks/rspec.rake", "tasks/website.rake"] s.has_rdoc = true - s.homepage = %q{http://auth-hmac.rubyforge.org} - s.post_install_message = %q{ -For more information on auth-hmac, see http://auth-hmac.rubyforge.org - -NOTE: Change this information in PostInstall.txt -You can also delete it if you don't want it. - - -} + s.homepage = %q{http://github.com/dnclabs/auth-hmac/} s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib"] s.rubyforge_project = %q{auth-hmac} diff --git a/config/hoe.rb b/config/hoe.rb index 966f6d8..dc645db 100644 --- a/config/hoe.rb +++ b/config/hoe.rb @@ -1,37 +1,13 @@ require 'auth-hmac/version' -AUTHOR = ['Sean Geoghegan', 'ascarter'] # can also be an array of Authors -EMAIL = "seangeo@gmail.com" -DESCRIPTION = "A gem providing HMAC based authentication for HTTP" -GEM_NAME = 'auth-hmac' # what ppl will type to install your gem -RUBYFORGE_PROJECT = 'auth-hmac' # The unix name for your project -HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org" -DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}" -EXTRA_DEPENDENCIES = [ -# ['activesupport', '>= 1.3.1'] -] # An array of rubygem dependencies [name, version] - -@config_file = "~/.rubyforge/user-config.yml" -@config = nil -RUBYFORGE_USERNAME = "unknown" -def rubyforge_username - unless @config - begin - @config = YAML.load(File.read(File.expand_path(@config_file))) - rescue - puts <<-EOS -ERROR: No rubyforge config file found: #{@config_file} -Run 'rubyforge setup' to prepare your env for access to Rubyforge - - See http://newgem.rubyforge.org/rubyforge.html for more details - EOS - exit - end - end - RUBYFORGE_USERNAME.replace @config["username"] -end - - -REV = nil +AUTHOR = ['Sean Geoghegan', 'ascarter', "Wes Morgan", "Adrian Cushman"] # can also be an array of Authors +EMAIL = "innovationlab@dnc.org" +DESCRIPTION = "A gem providing HMAC based authentication for HTTP. This is the DNC Labs fork." +GEM_NAME = 'dnclabs-auth-hmac' # what ppl will type to install your gem +HOMEPATH = "http://github.com/dnclabs/auth-hmac/" +RUBYFORGE_PROJECT = '' + +REV = '2010090201' # UNCOMMENT IF REQUIRED: # REV = YAML.load(`svn info`)['Revision'] VERS = AuthHMAC::VERSION::STRING + (REV ? ".#{REV}" : "") @@ -65,10 +41,4 @@ def extra_deps #p.extra_deps = EXTRA_DEPENDENCIES #p.spec_extras = {} # A hash of extra values to set in the gemspec. - end - -CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n") -PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}" -$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,'')) -$hoe.rsync_args = '-av --delete --ignore-errors' -$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue "" \ No newline at end of file +end diff --git a/config/requirements.rb b/config/requirements.rb index 9292b69..a9b8c4e 100644 --- a/config/requirements.rb +++ b/config/requirements.rb @@ -2,13 +2,13 @@ include FileUtils require 'rubygems' -%w[rake hoe newgem rubigen].each do |req_gem| +%w[rake hoe].each do |req_gem| begin require req_gem rescue LoadError puts "This Rakefile requires the '#{req_gem}' RubyGem." puts "Installation: gem install #{req_gem} -y" - exit + exit 1 end end diff --git a/lib/auth-hmac.rb b/lib/auth-hmac.rb index c522c4b..2288813 100644 --- a/lib/auth-hmac.rb +++ b/lib/auth-hmac.rb @@ -7,7 +7,6 @@ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) require 'openssl' -require 'base64' # This module provides a HMAC Authentication method for HTTP requests. It should work with # net/http request classes and CGIRequest classes and hence Rails. @@ -74,14 +73,21 @@ def find_header(keys, headers) class CanonicalString < String # :nodoc: include Headers - def initialize(request, authenticate_referrer) - self << request_method(request) + "\n" - self << header_values(headers(request)) + "\n" - self << request_path(request, authenticate_referrer) + def initialize(request, authenticate_referrer=false) + @request = request + @authenticate_referrer = authenticate_referrer + self << request_method + "\n" + self << header_values + "\n" + self << request_path end - + attr_reader :request, :authenticate_referrer + private - def request_method(request) + def headers + super(@request) + end + + def request_method if request.respond_to?(:request_method) && request.request_method.is_a?(String) request.request_method elsif request.respond_to?(:method) && request.method.is_a?(String) @@ -93,28 +99,50 @@ def request_method(request) end end - def header_values(headers) - [ content_type(headers), - content_md5(headers), - (date(headers) or headers['Date'] = Time.now.utc.httpdate) + def header_values + [ content_type, + (content_md5 or generated_md5), + (date or headers['Date'] = Time.now.utc.httpdate) ].join("\n") end - - def content_type(headers) + + def read_body + if request.body.respond_to?(:read) + body = request.body.read + request.body.rewind + body + else + request.body + end + end + + def content_type find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE), headers) end - def date(headers) + def date find_header(%w(DATE HTTP_DATE), headers) end - def content_md5(headers) - find_header(%w(CONTENT-MD5 CONTENT_MD5), headers) + def content_md5 + find_header(%w(CONTENT-MD5 CONTENT_MD5 HTTP_CONTENT_MD5), headers) + end + + def generated_md5 + if read_body.nil? || read_body.empty? + '' + else + headers['Content-MD5'] = generate_content_md5 + end + end + + def generate_content_md5 + OpenSSL::Digest::MD5.hexdigest(read_body) end - def request_path(request, authenticate_referrer) + def request_path if authenticate_referrer - headers(request)['Referer'] =~ /^(?:http:\/\/)?[^\/]*(\/.*)$/ + headers['Referer'] =~ /^(?:http:\/\/)?[^\/]*(\/.*)$/ path = $1 else # Try unparsed_uri in case it is a Webrick request @@ -165,6 +193,8 @@ def initialize(credential_store, options = nil) @signature_method = lambda { |r,ar| @signature_class.send(:new, r, ar) } end + attr_reader :service_id + # Generates canonical signing string for given request # # Supports same options as AuthHMAC.initialize for overriding service_id and @@ -242,7 +272,7 @@ def authenticated?(request) def signature(request, secret) digest = OpenSSL::Digest::Digest.new('sha1') - Base64.encode64(OpenSSL::HMAC.digest(digest, secret, canonical_string(request, @authenticate_referrer))).strip + [OpenSSL::HMAC.digest(digest, secret, canonical_string(request, @authenticate_referrer))].pack('m').strip end def canonical_string(request, authenticate_referrer=false) @@ -256,168 +286,4 @@ def authorization_header(request) def authorization(request, access_key_id, secret) "#{@service_id} #{access_key_id}:#{signature(request, secret)}" end - - # Integration with Rails - # - class Rails # :nodoc: - module ControllerFilter # :nodoc: - module ClassMethods - # Call within a Rails Controller to initialize HMAC authentication for the controller. - # - # * +credentials+ must be a hash that indexes secrets by their access key id. - # * +options+ supports the following arguments: - # * +failure_message+: The text to use when authentication fails. - # * +only+: A list off actions to protect. - # * +except+: A list of actions to not protect. - # * +hmac+: Options for HMAC creation. See AuthHMAC#initialize for options. - # - def with_auth_hmac(credentials, options = {}) - unless credentials.nil? - self.credentials = credentials - self.authhmac_failure_message = (options.delete(:failure_message) or "HMAC Authentication failed") - self.authhmac = AuthHMAC.new(self.credentials, options.delete(:hmac)) - before_filter(:hmac_login_required, options) - else - $stderr.puts("with_auth_hmac called with nil credentials - authentication will be skipped") - end - end - end - - module InstanceMethods # :nodoc: - def hmac_login_required - unless hmac_authenticated? - response.headers['WWW-Authenticate'] = 'AuthHMAC' - render :text => self.class.authhmac_failure_message, :status => :unauthorized - end - end - - def hmac_authenticated? - self.class.authhmac.nil? ? true : self.class.authhmac.authenticated?(request) - end - end - - unless defined?(ActionController) - begin - require 'rubygems' - gem 'actionpack' - gem 'activesupport' - require 'action_controller' - require 'active_support' - rescue - nil - end - end - - if defined?(ActionController::Base) - ActionController::Base.class_eval do - class_inheritable_accessor :authhmac - class_inheritable_accessor :credentials - class_inheritable_accessor :authhmac_failure_message - end - - ActionController::Base.send(:include, ControllerFilter::InstanceMethods) - ActionController::Base.extend(ControllerFilter::ClassMethods) - end - end - - module ActiveResourceExtension # :nodoc: - module BaseHmac # :nodoc: - def self.included(base) - base.extend(ClassMethods) - - base.class_inheritable_accessor :hmac_access_id - base.class_inheritable_accessor :hmac_secret - base.class_inheritable_accessor :use_hmac - base.class_inheritable_accessor :hmac_options - end - - module ClassMethods - # Call with an Active Resource class definition to sign - # all HTTP requests sent by that class with the provided - # credentials. - # - # Can be called with either a hash or two separate parameters - # like so: - # - # class MyResource < ActiveResource::Base - # with_auth_hmac("my_access_id", "my_secret") - # end - # - # or - # - # class MyOtherResource < ActiveResource::Base - # with_auth_hmac("my_access_id" => "my_secret") - # end - # - # - # This has only been tested with Rails 2.1 and since it is virtually a monkey - # patch of the internals of ActiveResource it might not work with past or - # future versions. - # - def with_auth_hmac(access_id, secret = nil, options = nil) - if access_id.is_a?(Hash) - self.hmac_access_id = access_id.keys.first - self.hmac_secret = access_id[self.hmac_access_id] - else - self.hmac_access_id = access_id - self.hmac_secret = secret - end - self.use_hmac = true - self.hmac_options = options - - class << self - alias_method_chain :connection, :hmac - end - end - - def connection_with_hmac(refresh = false) # :nodoc: - c = connection_without_hmac(refresh) - c.hmac_access_id = self.hmac_access_id - c.hmac_secret = self.hmac_secret - c.use_hmac = self.use_hmac - c.hmac_options = self.hmac_options - c - end - end - - module InstanceMethods # :nodoc: - end - end - - module Connection # :nodoc: - def self.included(base) - base.send :alias_method_chain, :request, :hmac - base.class_eval do - attr_accessor :hmac_secret, :hmac_access_id, :use_hmac, :hmac_options - end - end - - def request_with_hmac(method, path, *arguments) - if use_hmac && hmac_access_id && hmac_secret - arguments.last['Date'] = Time.now.httpdate if arguments.last['Date'].nil? - temp = "Net::HTTP::#{method.to_s.capitalize}".constantize.new(path, arguments.last) - AuthHMAC.sign!(temp, hmac_access_id, hmac_secret, hmac_options) - arguments.last['Authorization'] = temp['Authorization'] - end - - request_without_hmac(method, path, *arguments) - end - end - - unless defined?(ActiveResource) - begin - require 'rubygems' - gem 'activeresource' - require 'activeresource' - rescue - nil - end - end - - if defined?(ActiveResource) - ActiveResource::Base.send(:include, BaseHmac) - ActiveResource::Connection.send(:include, Connection) - end - end - end -end +end diff --git a/lib/auth-hmac/middleware.rb b/lib/auth-hmac/middleware.rb new file mode 100644 index 0000000..f3a47c8 --- /dev/null +++ b/lib/auth-hmac/middleware.rb @@ -0,0 +1,34 @@ +class AuthHMAC + class Middleware + def initialize(app, credentials) + @app = app + @hmac = AuthHMAC.new(credentials) + end + + def call(env) + dup.call!(env) + end + + def call!(env) + @env = env + + if @hmac.authenticated?(request) + rx = Regexp.new("#{@hmac.service_id} ([^:]+):(.+)$") + + if md = rx.match(@hmac.authorization_header(request)) + env["auth-hmac.access_key_id"] = md[1] + else + raise "Unknown request" + end + + @app.call(env) + else + Rack::Response.new("Authorization required", 401).finish + end + end + + def request + @request ||= Rack::Request.new(@env) + end + end +end diff --git a/spec/auth-hmac_spec.rb b/spec/auth-hmac_spec.rb index ab143d4..997becd 100644 --- a/spec/auth-hmac_spec.rb +++ b/spec/auth-hmac_spec.rb @@ -2,17 +2,12 @@ require "net/http" require 'time' require 'yaml' -require 'rubygems' -gem 'actionpack' -gem 'activeresource' -require 'action_controller' -require 'action_controller/test_process' -require 'active_resource' -require 'active_resource/http_mock' +require 'ruby-debug' +require 'active_support/core_ext/hash/except' # Class for doing a custom signature class CustomSignature < String - def initialize(request) + def initialize(request, authenticate_referrer=false) self << "Custom signature string: #{request.method}" end end @@ -65,6 +60,7 @@ def signature(value, secret) :service_id => 'MyService', :signature => CustomSignature } + # debugger AuthHMAC.sign!(@request, "my-key-id", "secret", options) @request['Authorization'].should == "MyService my-key-id:/L4N1v1BZSHfAYkQjsvZn696D9c=" end @@ -241,6 +237,7 @@ def signature(value, secret) rack_req.stub!(:request_method).and_return('GET') rack_req.stub!(:path).and_return("/path/to/get?foo=bar&bar=foo") rack_req.stub!(:[]).and_return({'foo' => 'bar', 'bar' => 'foo'}) + rack_req.stub!(:body).and_return(StringIO.new('')) @authhmac.authenticated?(rack_req).should be_true end end @@ -275,6 +272,18 @@ def signature(value, secret) request = Net::HTTP::Put.new("/", {'content-md5' => 'adsada'}) AuthHMAC::CanonicalString.new(request).should match(/adsada/) end + + it "should generate the content-md5 if one wasn't included and there is a request body" do + request = Net::HTTP::Put.new("/") + request.body = "foo=bar&baz=qux" + content_md5 = OpenSSL::Digest::MD5.hexdigest(request.body) + AuthHMAC::CanonicalString.new(request).should match(/#{content_md5}/) + end + + it "should not generate a content-md5 when there is no request body" do + request = Net::HTTP::Get.new("/") + AuthHMAC::CanonicalString.new(request).should match(/^GET\n\n\n/) + end it "should include the date" do date = Time.now.httpdate @@ -308,226 +317,4 @@ def signature(value, secret) AuthHMAC::CanonicalString.new(request).should == "GET\n\n\n#{date}\n/path/to/get" end end - - describe AuthHMAC::Rails::ControllerFilter do - class TestController < ActionController::Base - with_auth_hmac YAML.load(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml'))), - :only => [:index] - - def index - render :nothing => true, :status => :ok - end - - def public - render :nothing => true, :status => :ok - end - - def rescue_action(e) raise(e) end - end - - class MessageTestController < ActionController::Base - with_auth_hmac YAML.load(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml'))), - :failure_message => "Stay away!", :except => :public - - def index - render :nothing => true, :status => :ok - end - - def public - render :nothing => true, :status => :ok - end - - def rescue_action(e) raise(e) end - end - - class NilCredentialsController < ActionController::Base - with_auth_hmac nil - before_filter :force_auth - - def index - render :nothing => true, :status => :ok - end - - def public - render :nothing => true, :status => :ok - end - - def rescue_action(e) raise(e) end - - private - def force_auth - hmac_authenticated? - end - end - - class CustomTestController < ActionController::Base - with_auth_hmac YAML.load(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml'))), - :failure_message => "Stay away!", - :except => :public, - :hmac => { :service_id => 'MyService', :signature => CustomSignature } - - def index - render :nothing => true, :status => :ok - end - - def public - render :nothing => true, :status => :ok - end - - def rescue_action(e) raise(e) end - end - - describe NilCredentialsController do - it "should not raise an error when credentials are nil" do - request = ActionController::TestRequest.new - request.action = 'index' - request.path = "/index" - lambda do - NilCredentialsController.new.process(request, ActionController::TestResponse.new).code.should == "200" - end.should_not raise_error - end - end - - describe TestController do - it "should allow a request with the proper hmac" do - request = ActionController::TestRequest.new - request.env['Authorization'] = "AuthHMAC access key 1:6BVEVfAyIDoI3K+WallRMnDxROQ=" - request.env['DATE'] = "Thu, 10 Jul 2008 03:29:56 GMT" - request.action = 'index' - request.path = "/index" - TestController.new.process(request, ActionController::TestResponse.new).code.should == "200" - end - - it "should reject a request with no hmac" do - request = ActionController::TestRequest.new - request.action = 'index' - TestController.new.process(request, ActionController::TestResponse.new).code.should == "401" - end - - it "should reject a request with the wrong hmac" do - request = ActionController::TestRequest.new - request.action = 'index' - request.env['Authorization'] = "AuthHMAC bogus:bogus" - TestController.new.process(request, ActionController::TestResponse.new).code.should == "401" - end - - it "should include a WWW-Authenticate header with the schema AuthHMAC" do - request = ActionController::TestRequest.new - request.action = 'index' - request.env['Authorization'] = "AuthHMAC bogus:bogus" - TestController.new.process(request, ActionController::TestResponse.new).headers['WWW-Authenticate'].should == "AuthHMAC" - end - - it "should include a default error message" do - request = ActionController::TestRequest.new - request.action = 'index' - request.env['Authorization'] = "AuthHMAC bogus:bogus" - TestController.new.process(request, ActionController::TestResponse.new).body.should == "HMAC Authentication failed" - end - - it "should allow anything to access the public action (using only)" do - request = ActionController::TestRequest.new - request.action = 'public' - TestController.new.process(request, ActionController::TestResponse.new).code.should == "200" - end - end - - describe MessageTestController do - it "should reject a request with a given message" do - request = ActionController::TestRequest.new - request.action = 'index' - request.env['Authorization'] = "AuthHMAC bogus:bogus" - MessageTestController.new.process(request, ActionController::TestResponse.new).body.should == "Stay away!" - end - - it "should allow anything to access the public action (using except)" do - request = ActionController::TestRequest.new - request.action = 'public' - MessageTestController.new.process(request, ActionController::TestResponse.new).code.should == "200" - end - end - - describe CustomTestController do - it "should allow a request with the proper hmac" do - request = ActionController::TestRequest.new - request.env['Authorization'] = "MyService access key 1:J2W4dOrv/sGsL0C5adnZYiQ3d70=" - request.env['DATE'] = "Thu, 10 Jul 2008 03:29:56 GMT" - request.action = 'index' - request.path = "/index" - CustomTestController.new.process(request, ActionController::TestResponse.new).code.should == "200" - end - - it "should reject a request with no hmac" do - request = ActionController::TestRequest.new - request.action = 'index' - CustomTestController.new.process(request, ActionController::TestResponse.new).code.should == "401" - end - - it "should reject a request with the wrong hmac" do - request = ActionController::TestRequest.new - request.action = 'index' - request.env['Authorization'] = "AuthHMAC bogus:bogus" - CustomTestController.new.process(request, ActionController::TestResponse.new).code.should == "401" - end - - it "should reject a request with a given message" do - request = ActionController::TestRequest.new - request.action = 'index' - request.env['Authorization'] = "AuthHMAC bogus:bogus" - CustomTestController.new.process(request, ActionController::TestResponse.new).body.should == "Stay away!" - end - - it "should allow anything to access the public action (using except)" do - request = ActionController::TestRequest.new - request.action = 'public' - CustomTestController.new.process(request, ActionController::TestResponse.new).code.should == "200" - end - end - end - - describe AuthHMAC::Rails::ActiveResourceExtension do - class TestResource < ActiveResource::Base - with_auth_hmac("access_id", "secret") - self.site = "http://localhost/" - end - - class CustomTestResource < ActiveResource::Base - with_auth_hmac("access_id", "secret", { :service_id => 'MyService', :signature => CustomSignature }) - self.site = "http://localhost/" - end - - describe TestResource do - it "should send requests using HMAC authentication" do - now = Time.parse("Thu, 10 Jul 2008 03:29:56 GMT") - Time.should_receive(:now).at_least(1).and_return(now) - ActiveResource::HttpMock.respond_to do |mock| - mock.get "/test_resources/1.xml", - { - 'Authorization' => 'AuthHMAC access_id:44dvKATf4xanDtypqEA0EFYvOgI=', - 'Accept' => 'application/xml', - 'Date' => "Thu, 10 Jul 2008 03:29:56 GMT" - }, - { :id => "1" }.to_xml(:root => 'test_resource') - end - TestResource.find(1) - end - end - - describe CustomTestResource do - it "should send requests using HMAC authentication" do - now = Time.parse("Thu, 10 Jul 2008 03:29:56 GMT") - Time.should_receive(:now).at_least(1).and_return(now) - ActiveResource::HttpMock.respond_to do |mock| - mock.get "/custom_test_resources/1.xml", - { - 'Authorization' => 'MyService access_id:ZwCBL2rWLOMnwRrdF7wWEdJn7yA=', - 'Accept' => 'application/xml', - 'Date' => "Thu, 10 Jul 2008 03:29:56 GMT" - }, - { :id => "1" }.to_xml(:root => 'custom_test_resource') - end - CustomTestResource.find(1) - end - end - end end diff --git a/tasks/deployment.rake b/tasks/deployment.rake deleted file mode 100644 index 2f43742..0000000 --- a/tasks/deployment.rake +++ /dev/null @@ -1,34 +0,0 @@ -desc 'Release the website and new gem version' -task :deploy => [:check_version, :website, :release] do - puts "Remember to create SVN tag:" - puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " + - "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} " - puts "Suggested comment:" - puts "Tagging release #{CHANGES}" -end - -desc 'Runs tasks website_generate and install_gem as a local deployment of the gem' -task :local_deploy => [:website_generate, :install_gem] - -task :check_version do - unless ENV['VERSION'] - puts 'Must pass a VERSION=x.y.z release version' - exit - end - unless ENV['VERSION'] == VERS - puts "Please update your version.rb to match the release version, currently #{VERS}" - exit - end -end - -desc 'Install the package as a gem, without generating documentation(ri/rdoc)' -task :install_gem_no_doc => [:clean, :package] do - sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri" -end - -namespace :manifest do - desc 'Recreate Manifest.txt to include ALL files' - task :refresh do - `rake check_manifest | patch -p0 > Manifest.txt` - end -end \ No newline at end of file diff --git a/tasks/environment.rake b/tasks/environment.rake deleted file mode 100644 index 691ed3b..0000000 --- a/tasks/environment.rake +++ /dev/null @@ -1,7 +0,0 @@ -task :ruby_env do - RUBY_APP = if RUBY_PLATFORM =~ /java/ - "jruby" - else - "ruby" - end unless defined? RUBY_APP -end diff --git a/tasks/rspec.rake b/tasks/rspec.rake deleted file mode 100644 index 2415fa4..0000000 --- a/tasks/rspec.rake +++ /dev/null @@ -1,21 +0,0 @@ -begin - require 'spec' -rescue LoadError - require 'rubygems' - require 'spec' -end -begin - require 'spec/rake/spectask' -rescue LoadError - puts <<-EOS -To use rspec for testing you must install rspec gem: - gem install rspec -EOS - exit(0) -end - -desc "Run the specs under spec/models" -Spec::Rake::SpecTask.new do |t| - t.spec_opts = ['--options', "spec/spec.opts"] - t.spec_files = FileList['spec/**/*_spec.rb'] -end diff --git a/tasks/website.rake b/tasks/website.rake deleted file mode 100644 index 63081ec..0000000 --- a/tasks/website.rake +++ /dev/null @@ -1,9 +0,0 @@ -# stubs for the website generation -# To install the website framework: -# script/generate website - -task :website_generate - -task :website_upload - -task :website => :publish_docs