Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Runtime origin whitelist #13

Merged
merged 2 commits into from

2 participants

@boz
boz commented

Use a callback to determine whether or not an origin is allowed.

My particular use-case is for multi-tenancy: my origin whitelist depends on HTTP_HOST.

@cyu cyu merged commit b54d2aa into cyu:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 5, 2012
  1. @boz

    runtime origin whitelist support

    boz authored
Commits on Nov 7, 2012
  1. @boz
This page is out of date. Refresh to see the latest.
View
2  Gemfile
@@ -6,6 +6,6 @@ group :development do
gem "rake"
gem "shoulda"
gem "rack-test"
- gem "bundler", "~> 1.1.0"
+ gem "bundler", ">= 1.1.0"
gem "jeweler", "~> 1.8.3"
end
View
22 lib/rack/cors.rb
@@ -72,17 +72,17 @@ def all_resources
end
def process_preflight(env)
- resource = find_resource(env['HTTP_ORIGIN'], env['PATH_INFO'])
+ resource = find_resource(env['HTTP_ORIGIN'], env['PATH_INFO'],env)
resource && resource.process_preflight(env)
end
def process_cors(env)
- resource = find_resource(env['HTTP_ORIGIN'], env['PATH_INFO'])
+ resource = find_resource(env['HTTP_ORIGIN'], env['PATH_INFO'],env)
resource.to_headers(env) if resource
end
- def find_resource(origin, path)
- allowed = all_resources.detect {|r| r.allow_origin?(origin)}
+ def find_resource(origin, path, env)
+ allowed = all_resources.detect {|r| r.allow_origin?(origin,env)}
allowed ? allowed.find_resource(path) : nil
end
@@ -93,7 +93,7 @@ def initialize
@public_resources = false
end
- def origins(*args)
+ def origins(*args,&blk)
@origins = args.flatten.collect do |n|
case n
when Regexp, /^https?:\/\// then n
@@ -101,6 +101,7 @@ def origins(*args)
else "http://#{n}"
end
end
+ @origins.push(blk) if blk
end
def resource(path, opts={})
@@ -111,8 +112,15 @@ def public_resources?
@public_resources
end
- def allow_origin?(source)
- public_resources? || !!@origins.detect {|origin| origin === source}
+ def allow_origin?(source,env = {})
+ return true if public_resources?
+ return !! @origins.detect do |origin|
+ if origin.is_a?(Proc)
+ origin.call(source,env)
+ else
+ origin === source
+ end
+ end
end
def find_resource(path)
View
5 test/unit/cors_test.rb
@@ -26,6 +26,10 @@ def app
cors_request :origin => 'http://192.168.0.1:1234'
end
+ should 'support proc origins configuration' do
+ cors_request '/proc-origin', :origin => 'http://10.10.10.10:3000'
+ end
+
should 'support alternative X-Origin header' do
header 'X-Origin', 'http://localhost:3000'
get '/'
@@ -35,7 +39,6 @@ def app
should 'support expose header configuration' do
cors_request '/expose_single_header'
assert_equal 'expose-test', last_response.headers['Access-Control-Expose-Headers']
-
end
should 'support expose multiple header configuration' do
View
20 test/unit/dsl_test.rb
@@ -7,7 +7,10 @@ class DSLTest < Test::Unit::TestCase
should 'support explicit config object dsl mode' do
cors = Rack::Cors.new(Proc.new {}) do |cfg|
cfg.allow do |allow|
- allow.origins 'localhost:3000', '127.0.0.1:3000'
+ allow.origins 'localhost:3000', '127.0.0.1:3000' do |source,env|
+ source == "http://10.10.10.10:3000" &&
+ env["USER_AGENT"] == "test-agent"
+ end
allow.resource '/get-only', :methods => :get
allow.resource '/', :headers => :any
end
@@ -15,12 +18,19 @@ class DSLTest < Test::Unit::TestCase
resources = cors.send :all_resources
assert_equal 1, resources.length
assert resources.first.allow_origin?('http://localhost:3000')
+
+ assert resources.first.allow_origin?('http://10.10.10.10:3000',{"USER_AGENT" => "test-agent" })
+ assert !resources.first.allow_origin?('http://10.10.10.10:3001',{"USER_AGENT" => "test-agent" })
+ assert !resources.first.allow_origin?('http://10.10.10.10:3000',{"USER_AGENT" => "other-agent"})
end
should 'support implicit config object dsl mode' do
cors = Rack::Cors.new(Proc.new {}) do
allow do
- origins 'localhost:3000', '127.0.0.1:3000'
+ origins 'localhost:3000', '127.0.0.1:3000' do |source,env|
+ source == "http://10.10.10.10:3000" &&
+ env["USER_AGENT"] == "test-agent"
+ end
resource '/get-only', :methods => :get
resource '/', :headers => :any
end
@@ -28,5 +38,9 @@ class DSLTest < Test::Unit::TestCase
resources = cors.send :all_resources
assert_equal 1, resources.length
assert resources.first.allow_origin?('http://localhost:3000')
+
+ assert resources.first.allow_origin?('http://10.10.10.10:3000',{"USER_AGENT" => "test-agent" })
+ assert !resources.first.allow_origin?('http://10.10.10.10:3001',{"USER_AGENT" => "test-agent" })
+ assert !resources.first.allow_origin?('http://10.10.10.10:3000',{"USER_AGENT" => "other-agent"})
end
-end
+end
View
7 test/unit/test.ru
@@ -17,6 +17,13 @@ use Rack::Cors do
end
allow do
+ origins do |source,env|
+ source.end_with?("10.10.10.10:3000")
+ end
+ resource '/proc-origin'
+ end
+
+ allow do
origins '*'
resource '/public'
resource '/public_without_credentials', :credentials => false
Something went wrong with that request. Please try again.