Instiki 0.17.2: Security Release
This release upgrades Instiki to Rails 2.3.4, which patches two security holes in Rails. See http://weblog.rubyonrails.org/2009/9/4/ruby-on-rails-2-3-4 There are also some new features, and the usual boatload of bugfixes. See the CHANGELOG for details.
This commit is contained in:
parent
34c4306867
commit
4bdf703ab2
211 changed files with 3959 additions and 1325 deletions
|
@ -93,6 +93,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
|
||||
|
@ -112,6 +114,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
|
||||
|
@ -138,6 +153,7 @@ module ActiveResource
|
|||
# * 404 - ActiveResource::ResourceNotFound
|
||||
# * 405 - ActiveResource::MethodNotAllowed
|
||||
# * 409 - ActiveResource::ResourceConflict
|
||||
# * 410 - ActiveResource::ResourceGone
|
||||
# * 422 - ActiveResource::ResourceInvalid (rescued by save as validation errors)
|
||||
# * 401..499 - ActiveResource::ClientError
|
||||
# * 500..599 - ActiveResource::ServerError
|
||||
|
@ -158,7 +174,7 @@ module ActiveResource
|
|||
#
|
||||
# Active Resource supports validations on resources and will return errors if any these validations fail
|
||||
# (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
|
||||
# a response code of <tt>422</tt> and an XML representation of the validation errors. The save operation will
|
||||
# a response code of <tt>422</tt> and an XML or JSON representation of the validation errors. The save operation will
|
||||
# then fail (with a <tt>false</tt> return value) and the validation errors can be accessed on the resource in question.
|
||||
#
|
||||
# ryan = Person.find(1)
|
||||
|
@ -167,10 +183,14 @@ module ActiveResource
|
|||
#
|
||||
# # When
|
||||
# # PUT http://api.people.com:3000/people/1.xml
|
||||
# # or
|
||||
# # PUT http://api.people.com:3000/people/1.json
|
||||
# # is requested with invalid values, the response is:
|
||||
# #
|
||||
# # Response (422):
|
||||
# # <errors type="array"><error>First cannot be empty</error></errors>
|
||||
# # or
|
||||
# # {"errors":["First cannot be empty"]}
|
||||
# #
|
||||
#
|
||||
# ryan.errors.invalid?(:first) # => true
|
||||
|
@ -246,6 +266,22 @@ module ActiveResource
|
|||
end
|
||||
end
|
||||
|
||||
# Gets the \proxy variable if a proxy is required
|
||||
def proxy
|
||||
# Not using superclass_delegating_reader. See +site+ for explanation
|
||||
if defined?(@proxy)
|
||||
@proxy
|
||||
elsif superclass != Object && superclass.proxy
|
||||
superclass.proxy.dup.freeze
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the URI of the http proxy to the value in the +proxy+ argument.
|
||||
def proxy=(proxy)
|
||||
@connection = nil
|
||||
@proxy = proxy.nil? ? nil : create_proxy_uri_from(proxy)
|
||||
end
|
||||
|
||||
# Gets the \user for REST HTTP authentication.
|
||||
def user
|
||||
# Not using superclass_delegating_reader. See +site+ for explanation
|
||||
|
@ -315,15 +351,42 @@ 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>).
|
||||
def connection(refresh = false)
|
||||
if defined?(@connection) || superclass == Object
|
||||
@connection = Connection.new(site, format) if refresh || @connection.nil?
|
||||
@connection.proxy = proxy if proxy
|
||||
@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
|
||||
|
@ -557,7 +620,7 @@ module ActiveResource
|
|||
response.code.to_i == 200
|
||||
end
|
||||
# id && !find_single(id, options).nil?
|
||||
rescue ActiveResource::ResourceNotFound
|
||||
rescue ActiveResource::ResourceNotFound, ActiveResource::ResourceGone
|
||||
false
|
||||
end
|
||||
|
||||
|
@ -611,6 +674,11 @@ module ActiveResource
|
|||
site.is_a?(URI) ? site.dup : URI.parse(site)
|
||||
end
|
||||
|
||||
# Accepts a URI and creates the proxy URI from that.
|
||||
def create_proxy_uri_from(proxy)
|
||||
proxy.is_a?(URI) ? proxy.dup : URI.parse(proxy)
|
||||
end
|
||||
|
||||
# contains a set of the current prefix parameters.
|
||||
def prefix_parameters
|
||||
@prefix_parameters ||= prefix_source.scan(/:\w+/).map { |key| key[1..-1].to_sym }.to_set
|
||||
|
@ -952,7 +1020,13 @@ module ActiveResource
|
|||
case value
|
||||
when Array
|
||||
resource = find_or_create_resource_for_collection(key)
|
||||
value.map { |attrs| attrs.is_a?(String) ? attrs.dup : resource.new(attrs) }
|
||||
value.map do |attrs|
|
||||
if attrs.is_a?(String) || attrs.is_a?(Numeric)
|
||||
attrs.duplicable? ? attrs.dup : attrs
|
||||
else
|
||||
resource.new(attrs)
|
||||
end
|
||||
end
|
||||
when Hash
|
||||
resource = find_or_create_resource_for(key)
|
||||
resource.new(value)
|
||||
|
|
|
@ -26,6 +26,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
|
||||
|
@ -49,6 +57,9 @@ module ActiveResource
|
|||
# 409 Conflict
|
||||
class ResourceConflict < ClientError; end # :nodoc:
|
||||
|
||||
# 410 Gone
|
||||
class ResourceGone < ClientError; end # :nodoc:
|
||||
|
||||
# 5xx Server Error
|
||||
class ServerError < ConnectionError; end # :nodoc:
|
||||
|
||||
|
@ -67,10 +78,11 @@ module ActiveResource
|
|||
HTTP_FORMAT_HEADER_NAMES = { :get => 'Accept',
|
||||
:put => 'Content-Type',
|
||||
:post => 'Content-Type',
|
||||
:delete => 'Accept'
|
||||
:delete => 'Accept',
|
||||
:head => 'Accept'
|
||||
}
|
||||
|
||||
attr_reader :site, :user, :password, :timeout
|
||||
attr_reader :site, :user, :password, :timeout, :proxy, :ssl_options
|
||||
attr_accessor :format
|
||||
|
||||
class << self
|
||||
|
@ -95,7 +107,12 @@ module ActiveResource
|
|||
@password = URI.decode(@site.password) if @site.password
|
||||
end
|
||||
|
||||
# Set user for remote service.
|
||||
# Set the proxy for remote service.
|
||||
def proxy=(proxy)
|
||||
@proxy = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
|
||||
end
|
||||
|
||||
# Set the user for remote service.
|
||||
def user=(user)
|
||||
@user = user
|
||||
end
|
||||
|
@ -110,6 +127,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
|
||||
|
||||
# Execute a GET request.
|
||||
# Used to get (find) resources.
|
||||
def get(path, headers = {})
|
||||
|
@ -137,7 +159,7 @@ module ActiveResource
|
|||
# Execute a HEAD request.
|
||||
# Used to obtain meta-information about resources, such as whether they exist and their size (via response headers).
|
||||
def head(path, headers = {})
|
||||
request(:head, path, build_request_headers(headers))
|
||||
request(:head, path, build_request_headers(headers, :head))
|
||||
end
|
||||
|
||||
|
||||
|
@ -151,6 +173,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 remote service.
|
||||
|
@ -172,6 +196,8 @@ module ActiveResource
|
|||
raise(MethodNotAllowed.new(response))
|
||||
when 409
|
||||
raise(ResourceConflict.new(response))
|
||||
when 410
|
||||
raise(ResourceGone.new(response))
|
||||
when 422
|
||||
raise(ResourceInvalid.new(response))
|
||||
when 401...500
|
||||
|
@ -186,10 +212,49 @@ module ActiveResource
|
|||
# Creates new Net::HTTP instance for communication with
|
||||
# remote service and resources.
|
||||
def http
|
||||
http = Net::HTTP.new(@site.host, @site.port)
|
||||
http.use_ssl = @site.is_a?(URI::HTTPS)
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
|
||||
http.read_timeout = @timeout if @timeout # If timeout is not set, the default Net::HTTP timeout (60s) is used.
|
||||
configure_http(new_http)
|
||||
end
|
||||
|
||||
def new_http
|
||||
if @proxy
|
||||
Net::HTTP.new(@site.host, @site.port, @proxy.host, @proxy.port, @proxy.user, @proxy.password)
|
||||
else
|
||||
Net::HTTP.new(@site.host, @site.port)
|
||||
end
|
||||
end
|
||||
|
||||
def configure_http(http)
|
||||
http = apply_ssl_options(http)
|
||||
|
||||
# Net::HTTP timeouts default to 60 seconds.
|
||||
if @timeout
|
||||
http.open_timeout = @timeout
|
||||
http.read_timeout = @timeout
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
|
|
66
vendor/rails/activeresource/lib/active_resource/exceptions.rb
vendored
Normal file
66
vendor/rails/activeresource/lib/active_resource/exceptions.rb
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
module ActiveResource
|
||||
class ConnectionError < StandardError # :nodoc:
|
||||
attr_reader :response
|
||||
|
||||
def initialize(response, message = nil)
|
||||
@response = response
|
||||
@message = message
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when a Timeout::Error occurs.
|
||||
class TimeoutError < ConnectionError
|
||||
def initialize(message)
|
||||
@message = message
|
||||
end
|
||||
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
|
||||
end
|
||||
|
||||
# 4xx Client Error
|
||||
class ClientError < ConnectionError; end # :nodoc:
|
||||
|
||||
# 400 Bad Request
|
||||
class BadRequest < ClientError; end # :nodoc
|
||||
|
||||
# 401 Unauthorized
|
||||
class UnauthorizedAccess < ClientError; end # :nodoc
|
||||
|
||||
# 403 Forbidden
|
||||
class ForbiddenAccess < ClientError; end # :nodoc
|
||||
|
||||
# 404 Not Found
|
||||
class ResourceNotFound < ClientError; end # :nodoc:
|
||||
|
||||
# 409 Conflict
|
||||
class ResourceConflict < ClientError; end # :nodoc:
|
||||
|
||||
# 410 Gone
|
||||
class ResourceGone < ClientError; end # :nodoc:
|
||||
|
||||
# 5xx Server Error
|
||||
class ServerError < ConnectionError; end # :nodoc:
|
||||
|
||||
# 405 Method Not Allowed
|
||||
class MethodNotAllowed < ClientError # :nodoc:
|
||||
def allowed_methods
|
||||
@response['Allow'].split(',').map { |verb| verb.strip.downcase.to_sym }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -199,11 +199,10 @@ module ActiveResource
|
|||
alias_method :count, :size
|
||||
alias_method :length, :size
|
||||
|
||||
# Grabs errors from the XML response.
|
||||
def from_xml(xml)
|
||||
# Grabs errors from an array of messages (like ActiveRecord::Validations)
|
||||
def from_array(messages)
|
||||
clear
|
||||
humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) }
|
||||
messages = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
|
||||
messages.each do |message|
|
||||
attr_message = humanized_attributes.keys.detect do |attr_name|
|
||||
if message[0, attr_name.size + 1] == "#{attr_name} "
|
||||
|
@ -214,6 +213,18 @@ module ActiveResource
|
|||
add_to_base message if attr_message.nil?
|
||||
end
|
||||
end
|
||||
|
||||
# Grabs errors from the json response.
|
||||
def from_json(json)
|
||||
array = ActiveSupport::JSON.decode(json)['errors'] rescue []
|
||||
from_array array
|
||||
end
|
||||
|
||||
# Grabs errors from the XML response.
|
||||
def from_xml(xml)
|
||||
array = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
|
||||
from_array array
|
||||
end
|
||||
end
|
||||
|
||||
# Module to support validation and errors with Active Resource objects. The module overrides
|
||||
|
@ -248,7 +259,12 @@ module ActiveResource
|
|||
save_without_validation
|
||||
true
|
||||
rescue ResourceInvalid => error
|
||||
errors.from_xml(error.response.body)
|
||||
case error.response['Content-Type']
|
||||
when 'application/xml'
|
||||
errors.from_xml(error.response.body)
|
||||
when 'application/json'
|
||||
errors.from_json(error.response.body)
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ module ActiveResource
|
|||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 3
|
||||
TINY = 3
|
||||
TINY = 4
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue