aboutsummaryrefslogtreecommitdiffstats
path: root/activeresource/lib/active_resource
diff options
context:
space:
mode:
authorRoy Nicholson <nicholson.roy@gmail.com>2009-08-09 13:57:20 -0400
committerJeremy Kemper <jeremy@bitsweat.net>2009-08-09 13:24:05 -0700
commit3e0951632c52018eefb86d9e0bfe77383f9622fb (patch)
treed34dc23ad89395641345ff162ef6d0edde3403fa /activeresource/lib/active_resource
parentc5896bfd8432f6b7a1c6cb06486c5c85eafe9450 (diff)
downloadrails-3e0951632c52018eefb86d9e0bfe77383f9622fb.tar.gz
rails-3e0951632c52018eefb86d9e0bfe77383f9622fb.tar.bz2
rails-3e0951632c52018eefb86d9e0bfe77383f9622fb.zip
Add ability to set SSL options on ARes connections.
[#2370 state:committed] Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
Diffstat (limited to 'activeresource/lib/active_resource')
-rw-r--r--activeresource/lib/active_resource/base.rb41
-rw-r--r--activeresource/lib/active_resource/connection.rb35
-rw-r--r--activeresource/lib/active_resource/exceptions.rb8
3 files changed, 81 insertions, 3 deletions
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 9db35881b8..a66ce4c23f 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -103,6 +103,8 @@ module ActiveResource
#
# Many REST APIs will require authentication, usually in the form of basic
# HTTP authentication. Authentication can be specified by:
+ #
+ # === HTTP Basic Authentication
# * putting the credentials in the URL for the +site+ variable.
#
# class Person < ActiveResource::Base
@@ -123,6 +125,19 @@ module ActiveResource
# Note: Some values cannot be provided in the URL passed to site. e.g. email addresses
# as usernames. In those situations you should use the separate user and password option.
#
+ # === Certificate Authentication
+ #
+ # * End point uses an X509 certificate for authentication. <tt>See ssl_options=</tt> for all options.
+ #
+ # class Person < ActiveResource::Base
+ # self.site = "https://secure.api.people.com/"
+ # self.ssl_options = {:cert => OpenSSL::X509::Certificate.new(File.open(pem_file))
+ # :key => OpenSSL::PKey::RSA.new(File.open(pem_file)),
+ # :ca_path => "/path/to/OpenSSL/formatted/CA_Certs",
+ # :verify_mode => OpenSSL::SSL::VERIFY_PEER}
+ # end
+ #
+ #
# == Errors & Validation
#
# Error handling and validation is handled in much the same manner as you're used to seeing in
@@ -342,6 +357,31 @@ module ActiveResource
end
end
+ # Options that will get applied to an SSL connection.
+ #
+ # * <tt>:key</tt> - An OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
+ # * <tt>:cert</tt> - An OpenSSL::X509::Certificate object as client certificate
+ # * <tt>:ca_file</tt> - Path to a CA certification file in PEM format. The file can contrain several CA certificates.
+ # * <tt>:ca_path</tt> - Path of a CA certification directory containing certifications in PEM format.
+ # * <tt>:verify_mode</tt> - Flags for server the certification verification at begining of SSL/TLS session. (OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable)
+ # * <tt>:verify_callback</tt> - The verify callback for the server certification verification.
+ # * <tt>:verify_depth</tt> - The maximum depth for the certificate chain verification.
+ # * <tt>:cert_store</tt> - OpenSSL::X509::Store to verify peer certificate.
+ # * <tt>:ssl_timeout</tt> -The SSL timeout in seconds.
+ def ssl_options=(opts={})
+ @connection = nil
+ @ssl_options = opts
+ end
+
+ # Returns the SSL options hash.
+ def ssl_options
+ if defined?(@ssl_options)
+ @ssl_options
+ elsif superclass != Object && superclass.ssl_options
+ superclass.ssl_options
+ end
+ end
+
# An instance of ActiveResource::Connection that is the base \connection to the remote service.
# The +refresh+ parameter toggles whether or not the \connection is refreshed at every request
# or not (defaults to <tt>false</tt>).
@@ -352,6 +392,7 @@ module ActiveResource
@connection.user = user if user
@connection.password = password if password
@connection.timeout = timeout if timeout
+ @connection.ssl_options = ssl_options if ssl_options
@connection
else
superclass.connection
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index ef57c1f8b2..c08b7272ae 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -16,7 +16,7 @@ module ActiveResource
:delete => 'Accept'
}
- attr_reader :site, :user, :password, :timeout, :proxy
+ attr_reader :site, :user, :password, :timeout, :proxy, :ssl_options
attr_accessor :format
class << self
@@ -61,6 +61,11 @@ module ActiveResource
@timeout = timeout
end
+ # Hash of options applied to Net::HTTP instance when +site+ protocol is 'https'.
+ def ssl_options=(opts={})
+ @ssl_options = opts
+ end
+
# Executes a GET request.
# Used to get (find) resources.
def get(path, headers = {})
@@ -102,6 +107,8 @@ module ActiveResource
handle_response(result)
rescue Timeout::Error => e
raise TimeoutError.new(e.message)
+ rescue OpenSSL::SSL::SSLError => e
+ raise SSLError.new(e.message)
end
# Handles response and error codes from the remote service.
@@ -149,8 +156,7 @@ module ActiveResource
end
def configure_http(http)
- http.use_ssl = @site.is_a?(URI::HTTPS)
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl?
+ http = apply_ssl_options(http)
# Net::HTTP timeouts default to 60 seconds.
if @timeout
@@ -161,6 +167,29 @@ module ActiveResource
http
end
+ def apply_ssl_options(http)
+ return http unless @site.is_a?(URI::HTTPS)
+
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ return http unless defined?(@ssl_options)
+
+ http.ca_path = @ssl_options[:ca_path] if @ssl_options[:ca_path]
+ http.ca_file = @ssl_options[:ca_file] if @ssl_options[:ca_file]
+
+ http.cert = @ssl_options[:cert] if @ssl_options[:cert]
+ http.key = @ssl_options[:key] if @ssl_options[:key]
+
+ http.cert_store = @ssl_options[:cert_store] if @ssl_options[:cert_store]
+ http.ssl_timeout = @ssl_options[:ssl_timeout] if @ssl_options[:ssl_timeout]
+
+ http.verify_mode = @ssl_options[:verify_mode] if @ssl_options[:verify_mode]
+ http.verify_callback = @ssl_options[:verify_callback] if @ssl_options[:verify_callback]
+ http.verify_depth = @ssl_options[:verify_depth] if @ssl_options[:verify_depth]
+
+ http
+ end
+
def default_header
@default_header ||= {}
end
diff --git a/activeresource/lib/active_resource/exceptions.rb b/activeresource/lib/active_resource/exceptions.rb
index 5e4b1d4487..dd59146b1a 100644
--- a/activeresource/lib/active_resource/exceptions.rb
+++ b/activeresource/lib/active_resource/exceptions.rb
@@ -20,6 +20,14 @@ module ActiveResource
def to_s; @message ;end
end
+ # Raised when a OpenSSL::SSL::SSLError occurs.
+ class SSLError < ConnectionError
+ def initialize(message)
+ @message = message
+ end
+ def to_s; @message ;end
+ end
+
# 3xx Redirection
class Redirection < ConnectionError # :nodoc:
def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end