Merge branch 'allowed_service_ips'
Conflicts: lib/casserver/server.rb spec/spec_helper.rb
This commit is contained in:
Коммит
d323c3af93
|
@ -532,3 +532,12 @@ log:
|
|||
# convert this to "jsmith".
|
||||
|
||||
#downcase_username: true
|
||||
|
||||
# If you'd like to limit the service hosts that can use CAS for authentication,
|
||||
# add the individual IPs and IP ranges in CIDR notation below. Leaving this
|
||||
# setting blank will allow any server to authenticate users via the CAS server
|
||||
# and potentially harvest sensitive user information.
|
||||
|
||||
#allowed_service_ips:
|
||||
# - 127.0.0.1
|
||||
# - 192.168.0.0/24
|
||||
|
|
|
@ -29,6 +29,7 @@ GEM
|
|||
xpath (~> 0.1.4)
|
||||
childprocess (0.3.5)
|
||||
ffi (~> 1.0, >= 1.0.6)
|
||||
crack (0.3.1)
|
||||
crypt-isaac (0.9.1)
|
||||
diff-lcs (1.1.3)
|
||||
ffi (1.1.5)
|
||||
|
@ -77,6 +78,9 @@ GEM
|
|||
sqlite3 (1.3.6)
|
||||
thor (0.16.0)
|
||||
tilt (1.3.3)
|
||||
webmock (1.9.0)
|
||||
addressable (>= 2.2.7)
|
||||
crack (>= 0.1.7)
|
||||
xpath (0.1.4)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
|
@ -92,6 +96,7 @@ DEPENDENCIES
|
|||
guard (~> 1.4.0)
|
||||
guard-rspec (= 2.0.0)
|
||||
net-ldap (~> 0.1.1)
|
||||
nokogiri (~> 1.3)
|
||||
rack-test
|
||||
rake (= 0.8.7)
|
||||
rb-fsevent (~> 0.9.2)
|
||||
|
@ -99,3 +104,4 @@ DEPENDENCIES
|
|||
rspec-core
|
||||
rubycas-server!
|
||||
sqlite3 (~> 1.3.1)
|
||||
webmock (~> 1.8)
|
||||
|
|
|
@ -39,6 +39,7 @@ GEM
|
|||
xpath (~> 0.1.4)
|
||||
childprocess (0.3.5)
|
||||
ffi (~> 1.0, >= 1.0.6)
|
||||
crack (0.3.1)
|
||||
crypt-isaac (0.9.1)
|
||||
diff-lcs (1.1.3)
|
||||
ffi (1.1.5)
|
||||
|
@ -89,6 +90,9 @@ GEM
|
|||
thor (0.16.0)
|
||||
tilt (1.3.3)
|
||||
tzinfo (0.3.33)
|
||||
webmock (1.9.0)
|
||||
addressable (>= 2.2.7)
|
||||
crack (>= 0.1.7)
|
||||
xpath (0.1.4)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
|
@ -104,6 +108,7 @@ DEPENDENCIES
|
|||
guard (~> 1.4.0)
|
||||
guard-rspec (= 2.0.0)
|
||||
net-ldap (~> 0.1.1)
|
||||
nokogiri (~> 1.3)
|
||||
rack-test
|
||||
rake (= 0.8.7)
|
||||
rb-fsevent (~> 0.9.2)
|
||||
|
@ -111,3 +116,4 @@ DEPENDENCIES
|
|||
rspec-core
|
||||
rubycas-server!
|
||||
sqlite3 (~> 1.3.1)
|
||||
webmock (~> 1.8)
|
||||
|
|
|
@ -40,6 +40,7 @@ GEM
|
|||
xpath (~> 0.1.4)
|
||||
childprocess (0.3.5)
|
||||
ffi (~> 1.0, >= 1.0.6)
|
||||
crack (0.3.1)
|
||||
crypt-isaac (0.9.1)
|
||||
diff-lcs (1.1.3)
|
||||
ffi (1.1.5)
|
||||
|
@ -90,6 +91,9 @@ GEM
|
|||
thor (0.16.0)
|
||||
tilt (1.3.3)
|
||||
tzinfo (0.3.33)
|
||||
webmock (1.9.0)
|
||||
addressable (>= 2.2.7)
|
||||
crack (>= 0.1.7)
|
||||
xpath (0.1.4)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
|
@ -105,6 +109,7 @@ DEPENDENCIES
|
|||
guard (~> 1.4.0)
|
||||
guard-rspec (= 2.0.0)
|
||||
net-ldap (~> 0.1.1)
|
||||
nokogiri (~> 1.3)
|
||||
rack-test
|
||||
rake (= 0.8.7)
|
||||
rb-fsevent (~> 0.9.2)
|
||||
|
@ -112,3 +117,4 @@ DEPENDENCIES
|
|||
rspec-core
|
||||
rubycas-server!
|
||||
sqlite3 (~> 1.3.1)
|
||||
webmock (~> 1.8)
|
||||
|
|
|
@ -40,6 +40,7 @@ GEM
|
|||
xpath (~> 0.1.4)
|
||||
childprocess (0.3.5)
|
||||
ffi (~> 1.0, >= 1.0.6)
|
||||
crack (0.3.1)
|
||||
crypt-isaac (0.9.1)
|
||||
diff-lcs (1.1.3)
|
||||
ffi (1.1.5)
|
||||
|
@ -90,6 +91,9 @@ GEM
|
|||
thor (0.16.0)
|
||||
tilt (1.3.3)
|
||||
tzinfo (0.3.33)
|
||||
webmock (1.9.0)
|
||||
addressable (>= 2.2.7)
|
||||
crack (>= 0.1.7)
|
||||
xpath (0.1.4)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
|
@ -105,6 +109,7 @@ DEPENDENCIES
|
|||
guard (~> 1.4.0)
|
||||
guard-rspec (= 2.0.0)
|
||||
net-ldap (~> 0.1.1)
|
||||
nokogiri (~> 1.3)
|
||||
rack-test
|
||||
rake (= 0.8.7)
|
||||
rb-fsevent (~> 0.9.2)
|
||||
|
@ -112,3 +117,4 @@ DEPENDENCIES
|
|||
rspec-core
|
||||
rubycas-server!
|
||||
sqlite3 (~> 1.3.1)
|
||||
webmock (~> 1.8)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
require 'active_support'
|
||||
require 'active_support/hash_with_indifferent_access'
|
||||
require 'active_support/core_ext'
|
||||
|
||||
module CASServer
|
||||
|
|
|
@ -600,58 +600,68 @@ module CASServer
|
|||
# 2.4
|
||||
|
||||
# 2.4.1
|
||||
get "#{uri_path}/validate" do
|
||||
CASServer::Utils::log_controller_action(self.class, params)
|
||||
get "#{uri_path}/validate" do
|
||||
CASServer::Utils::log_controller_action(self.class, params)
|
||||
|
||||
# required
|
||||
@service = clean_service_url(params['service'])
|
||||
@ticket = params['ticket']
|
||||
# optional
|
||||
@renew = params['renew']
|
||||
if ip_allowed?(request.ip)
|
||||
# required
|
||||
@service = clean_service_url(params['service'])
|
||||
@ticket = params['ticket']
|
||||
# optional
|
||||
@renew = params['renew']
|
||||
|
||||
st, @error = validate_service_ticket(@service, @ticket)
|
||||
@success = st && !@error
|
||||
st, @error = validate_service_ticket(@service, @ticket)
|
||||
@success = st && !@error
|
||||
|
||||
@username = st.username if @success
|
||||
@username = st.username if @success
|
||||
else
|
||||
@success = false
|
||||
@error = Error.new(:INVALID_REQUEST, 'The IP address of this service has not been allowed')
|
||||
end
|
||||
|
||||
status response_status_from_error(@error) if @error
|
||||
|
||||
render @template_engine, :validate, :layout => false
|
||||
end
|
||||
render @template_engine, :validate, :layout => false
|
||||
end
|
||||
|
||||
|
||||
# 2.5
|
||||
|
||||
# 2.5.1
|
||||
get "#{uri_path}/serviceValidate" do
|
||||
CASServer::Utils::log_controller_action(self.class, params)
|
||||
CASServer::Utils::log_controller_action(self.class, params)
|
||||
|
||||
# force xml content type
|
||||
content_type 'text/xml', :charset => 'utf-8'
|
||||
|
||||
# required
|
||||
@service = clean_service_url(params['service'])
|
||||
@ticket = params['ticket']
|
||||
# optional
|
||||
@pgt_url = params['pgtUrl']
|
||||
@renew = params['renew']
|
||||
if ip_allowed?(request.ip)
|
||||
# required
|
||||
@service = clean_service_url(params['service'])
|
||||
@ticket = params['ticket']
|
||||
# optional
|
||||
@pgt_url = params['pgtUrl']
|
||||
@renew = params['renew']
|
||||
|
||||
st, @error = validate_service_ticket(@service, @ticket)
|
||||
@success = st && !@error
|
||||
st, @error = validate_service_ticket(@service, @ticket)
|
||||
@success = st && !@error
|
||||
|
||||
if @success
|
||||
@username = st.username
|
||||
if @pgt_url
|
||||
pgt = generate_proxy_granting_ticket(@pgt_url, st)
|
||||
@pgtiou = pgt.iou if pgt
|
||||
if @success
|
||||
@username = st.username
|
||||
if @pgt_url
|
||||
pgt = generate_proxy_granting_ticket(@pgt_url, st)
|
||||
@pgtiou = pgt.iou if pgt
|
||||
end
|
||||
@extra_attributes = st.granted_by_tgt.extra_attributes || {}
|
||||
end
|
||||
@extra_attributes = st.granted_by_tgt.extra_attributes || {}
|
||||
else
|
||||
@success = false
|
||||
@error = Error.new(:INVALID_REQUEST, 'The IP address of this service has not been allowed')
|
||||
end
|
||||
|
||||
status response_status_from_error(@error) if @error
|
||||
|
||||
render :builder, :proxy_validate
|
||||
end
|
||||
render :builder, :proxy_validate
|
||||
end
|
||||
|
||||
|
||||
# 2.6
|
||||
|
@ -663,32 +673,38 @@ module CASServer
|
|||
# force xml content type
|
||||
content_type 'text/xml', :charset => 'utf-8'
|
||||
|
||||
# required
|
||||
@service = clean_service_url(params['service'])
|
||||
@ticket = params['ticket']
|
||||
# optional
|
||||
@pgt_url = params['pgtUrl']
|
||||
@renew = params['renew']
|
||||
if ip_allowed?(request.ip)
|
||||
|
||||
@proxies = []
|
||||
# required
|
||||
@service = clean_service_url(params['service'])
|
||||
@ticket = params['ticket']
|
||||
# optional
|
||||
@pgt_url = params['pgtUrl']
|
||||
@renew = params['renew']
|
||||
|
||||
t, @error = validate_proxy_ticket(@service, @ticket)
|
||||
@success = t && !@error
|
||||
@proxies = []
|
||||
|
||||
@extra_attributes = {}
|
||||
if @success
|
||||
@username = t.username
|
||||
t, @error = validate_proxy_ticket(@service, @ticket)
|
||||
@success = t && !@error
|
||||
|
||||
if t.kind_of? CASServer::Model::ProxyTicket
|
||||
@proxies << t.granted_by_pgt.service_ticket.service
|
||||
@extra_attributes = {}
|
||||
if @success
|
||||
@username = t.username
|
||||
|
||||
if t.kind_of? CASServer::Model::ProxyTicket
|
||||
@proxies << t.granted_by_pgt.service_ticket.service
|
||||
end
|
||||
|
||||
if @pgt_url
|
||||
pgt = generate_proxy_granting_ticket(@pgt_url, t)
|
||||
@pgtiou = pgt.iou if pgt
|
||||
end
|
||||
|
||||
@extra_attributes = t.granted_by_tgt.extra_attributes || {}
|
||||
end
|
||||
|
||||
if @pgt_url
|
||||
pgt = generate_proxy_granting_ticket(@pgt_url, t)
|
||||
@pgtiou = pgt.iou if pgt
|
||||
end
|
||||
|
||||
@extra_attributes = t.granted_by_tgt.extra_attributes || {}
|
||||
else
|
||||
@success = false
|
||||
@error = Error.new(:INVALID_REQUEST, 'The IP address of this service has not been allowed')
|
||||
end
|
||||
|
||||
status response_status_from_error(@error) if @error
|
||||
|
@ -751,6 +767,14 @@ module CASServer
|
|||
super engine, data, options, views
|
||||
end
|
||||
|
||||
def ip_allowed?(ip)
|
||||
require 'ipaddr'
|
||||
|
||||
allowed_ips = Array(settings.config[:allowed_service_ips])
|
||||
|
||||
allowed_ips.empty? || allowed_ips.any? { |i| IPAddr.new(i) === ip }
|
||||
end
|
||||
|
||||
helpers do
|
||||
def authenticated?
|
||||
@authenticated
|
||||
|
@ -761,4 +785,4 @@ module CASServer
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -141,27 +141,80 @@ describe 'CASServer' do
|
|||
end
|
||||
end
|
||||
|
||||
describe "proxyValidate" do
|
||||
describe 'validation' do
|
||||
let(:allowed_ip) { '127.0.0.1' }
|
||||
let(:unallowed_ip) { '10.0.0.1' }
|
||||
let(:service) { @target_service }
|
||||
|
||||
before do
|
||||
load_server("default_config")
|
||||
load_server('default_config') # 127.0.0.0/24 is allowed here
|
||||
reset_spec_database
|
||||
|
||||
visit "/login?service="+CGI.escape(@target_service)
|
||||
ticket = get_ticket_for(service)
|
||||
|
||||
fill_in 'username', :with => VALID_USERNAME
|
||||
fill_in 'password', :with => VALID_PASSWORD
|
||||
|
||||
click_button 'login-submit'
|
||||
|
||||
page.current_url.should =~ /^#{Regexp.escape(@target_service)}\/?\?ticket=ST\-[1-9rA-Z]+/
|
||||
@ticket = page.current_url.match(/ticket=(.*)$/)[1]
|
||||
Rack::Request.any_instance.stub(:ip).and_return(request_ip)
|
||||
get "/#{path}?service=#{CGI.escape(service)}&ticket=#{CGI.escape(ticket)}"
|
||||
end
|
||||
|
||||
it "should have extra attributes in proper format" do
|
||||
get "/serviceValidate?service=#{CGI.escape(@target_service)}&ticket=#{@ticket}"
|
||||
subject { last_response }
|
||||
|
||||
last_response.content_type.should match 'text/xml'
|
||||
last_response.body.should match "<test_utf_string>Ютф</test_utf_string>"
|
||||
describe 'validate' do
|
||||
let(:path) { 'validate' }
|
||||
|
||||
context 'from allowed IP' do
|
||||
let(:request_ip) { allowed_ip }
|
||||
|
||||
it { should be_ok }
|
||||
its(:body) { should match 'yes' }
|
||||
end
|
||||
|
||||
context 'from unallowed IP' do
|
||||
let(:request_ip) { unallowed_ip }
|
||||
|
||||
its(:status) { should eql 422 }
|
||||
its(:body) { should match 'no' }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'serviceValidate' do
|
||||
let(:path) { 'serviceValidate' }
|
||||
|
||||
context 'from allowed IP' do
|
||||
let(:request_ip) { allowed_ip }
|
||||
|
||||
it { should be_ok }
|
||||
its(:content_type) { should match 'text/xml' }
|
||||
its(:body) { should match /cas:authenticationSuccess/i }
|
||||
its(:body) { should match '<test_utf_string>Ютф</test_utf_string>' }
|
||||
end
|
||||
|
||||
context 'from unallowed IP' do
|
||||
let(:request_ip) { unallowed_ip }
|
||||
|
||||
its(:status) { should eql 422 }
|
||||
its(:content_type) { should match 'text/xml' }
|
||||
its(:body) { should match /cas:authenticationFailure.*INVALID_REQUEST/i }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'proxyValidate' do
|
||||
let(:path) { 'proxyValidate' }
|
||||
|
||||
context 'from allowed IP' do
|
||||
let(:request_ip) { allowed_ip }
|
||||
|
||||
it { should be_ok }
|
||||
its(:content_type) { should match 'text/xml' }
|
||||
its(:body) { should match /cas:authenticationSuccess/i }
|
||||
end
|
||||
|
||||
context 'from unallowed IP' do
|
||||
let(:request_ip) { unallowed_ip }
|
||||
|
||||
its(:status) { should eql 422 }
|
||||
its(:content_type) { should match 'text/xml' }
|
||||
its(:body) { should match /cas:authenticationFailure.*INVALID_REQUEST/i }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -48,3 +48,6 @@ enable_single_sign_out: true
|
|||
#maximum_session_lifetime: 172800
|
||||
|
||||
#downcase_username: true
|
||||
|
||||
allowed_service_ips:
|
||||
- 127.0.0.0/24
|
|
@ -109,6 +109,14 @@ def reset_spec_database
|
|||
ActiveRecord::Migrator.migrate("db/migrate")
|
||||
end
|
||||
|
||||
def get_ticket_for(service, username = 'spec_user', password = 'spec_password')
|
||||
visit "/login?service=#{CGI.escape(service)}"
|
||||
fill_in 'username', :with => username
|
||||
fill_in 'password', :with => password
|
||||
click_button 'login-submit'
|
||||
|
||||
page.current_url.match(/ticket=(.*)$/)[1]
|
||||
end
|
||||
def gem_available?(name)
|
||||
if Gem::Specification.methods.include?(:find_all_by_name)
|
||||
not Gem::Specification.find_all_by_name(name).empty?
|
||||
|
|
Загрузка…
Ссылка в новой задаче