In standalone mode, Cantaloupe has built-in support for HTTP Basic authentication. To enable it, set the following keys in the configuration file:
auth.basic.enabled = true
auth.basic.username = myusername
auth.basic.secret = mypassword
When enabled, the entire website and all endpoints will be restricted.
A custom delegate method can be used to implement authorization logic ranging from simple to complex. The image server will invoke this method upon every image request and, depending on its return value, either:
The delegate method in question is called authorized?
. A skeleton with documented parameters and return values is present in the delegates.rb.sample file. By default, it just returns true
, authorizing all requests.
This method will print the parameters to the console.
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
puts "identifier: #{identifier}"
puts "full_size: #{full_size}"
puts "operations: #{operations}"
puts "resulting_size: #{resulting_size}"
puts "output_format: #{output_format}"
puts "request_uri: #{request_uri}"
puts "request_headers: #{request_headers}"
puts "client_ip: #{client_ip}"
puts "cookies: #{cookies}"
true
end
end
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
scale = operations.select{ |op| op['class'] == 'Scale' }.first
if scale
max_scale = 0.5
return scale['width'] <= full_size['width'] * max_scale and
scale['height'] <= full_size['height'] * max_scale
end
false
end
end
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
# Allow only identifiers that don't include "_restricted"
return !identifier.include?('_restricted')
# Allow only identifiers that start with "_public"
return identifier.start_with?('public_')
# Allow only identifiers matching a regex
return identifier.match(/^image[5-9][0-9]/)
end
end
(You will need to install the MySQL JDBC driver first.)
authorized?
are not guaranteed to be safe. identifier
, for example, will be exactly as supplied in the URL. Always prefer prepared statements over string concatenation in order to reduce susceptibility to SQL injection attacks.module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
require "rubygems"
require "jdbc/mysql"
require "java"
authorized = false
Java::com.mysql.jdbc.Driver
url = "jdbc:mysql://HOST/DATABASE"
conn = java.sql.DriverManager.get_connection(url, "USERNAME", "PASSWORD")
stmt = conn.create_statement
begin
query = %q{SELECT is_public
FROM image
WHERE identifier = ?
LIMIT 1}
stmt = conn.prepare_statement(query)
stmt.setString(1, identifier);
result_set = stmt.execute_query
while result_set.next do
authorized = result_set.getBoolean(1)
end
ensure
stmt.close
conn.close
end
authorized
end
end
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
output_format['media_type'] == 'image/jpeg'
end
end
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
agent = request_headers.select{ |h, v| h.downcase == 'user-agent' }.first
agent == 'MyAllowedUserAgent/1.0'
end
end
If you have an authorization service that sets a cookie, you can check for it. Cookies can't be shared across domains, but this could still work if you can set the cookie on a parent domain.
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
cookies.select{ |c| c['authcookie'] }.any?
end
end
In this example, requests for images containing any part of the bottom right quadrant of the source image will be denied.
(Also see redaction.)
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
crop = operations.select{ |op| op['class'] == 'Crop' }.first
if crop
max_x = full_size['width'] / 2
max_y = full_size['height'] / 2
return !(crop['x'] + crop['width'] > max_x and
crop['y'] + crop['height'] > max_y)
end
false
end
end
module Cantaloupe
def self.authorized?(identifier, full_size, operations, resulting_size,
output_format, request_uri, request_headers, client_ip,
cookies)
{
'location' => 'http://example.org/some-other-url',
'status_code' => 302
}
end
end