Skip to content

Commit b2435c9

Browse files
committed
Merge branch 'release_1.101'
2 parents 4c1b7bd + e6f62bd commit b2435c9

6 files changed

Lines changed: 147 additions & 70 deletions

File tree

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,55 @@
11
# Does not inherit from ApplicationController to avoid requiring sign-in here
22
class SessionsController < ActionController::Base
33
require 'net/http'
4-
5-
def cas_reg
6-
"https://cas-reg.uits.iu.edu"
7-
end
8-
def cas
9-
"https://cas.iu.edu"
10-
end
11-
124
# Prevent CSRF attacks by raising an exception.
135
# For APIs, you may want to use :null_session instead.
146
protect_from_forgery with: :exception
157
include SessionsHelper
8+
before_action :set_cas_ticket, only: [:new, :validate_login]
9+
before_action :set_cas_user, only: [:validate_login]
1610

1711
def new
18-
redirect_to("#{cas}/cas/login?cassvc=ANY&casurl=#{root_url}sessions/validate_login")
12+
@cas_ticket.present? ? validate_login : redirect_to(cas_url(:login, service: secure_root_url))
1913
end
2014

2115
def validate_login
22-
@casticket=params[:casticket]
23-
uri = URI.parse("#{cas}/cas/validate?cassvc=ANY&casticket=#{@casticket}&casurl=#{root_url}")
24-
request = Net::HTTP.new(uri.host, uri.port)
25-
request.use_ssl = true
26-
request.verify_mode = OpenSSL::SSL::VERIFY_NONE
27-
response = request.get("#{cas}/cas/validate?cassvc=ANY&casticket=#{@casticket}&casurl=#{root_url}")
28-
@resp = response.body
29-
if @resp.slice(0,3) == 'yes'
30-
@resp_true = @resp.slice(0,3)
31-
@nlength=@resp.length - 7
32-
@resp_user=@resp.slice(5,@nlength)
33-
if User.authenticate(@resp_user)
34-
sign_in(@resp_user)
35-
redirect_back_or_to root_url
36-
else
37-
redirect_to "#{root_url}denied.html"
38-
end
16+
set_cas_user if @cas_user.blank?
17+
if @cas_user.present? && User.authenticate(@cas_user)
18+
sign_in(@cas_user)
19+
redirect_back_or_to secure_root_url
3920
else
40-
@resp_true = @resp.slice(0,2)
41-
redirect_to "#{root_url}denied.html"
21+
redirect_to "#{secure_root_url}denied.html"
4222
end
4323
end
4424

4525
def destroy
4626
sign_out
47-
redirect_to 'https://cas.iu.edu/cas/logout'
27+
redirect_to(cas_url(:logout))
4828
end
4929

30+
private
31+
def cas_url(action = nil, **keywords)
32+
url_string = Pod.config[:auth][:cas_host] + Pod.config[:auth]["cas_#{action}_url"].to_s
33+
url_string += ("?" + keywords.map { |k, v| "#{k}=#{v}" }.join('&')) if keywords.any?
34+
url_string
35+
end
36+
37+
def set_cas_ticket
38+
@cas_ticket = params[:ticket]
39+
end
40+
41+
def set_cas_user
42+
begin
43+
uri = URI.parse(cas_url(:validate, ticket: @cas_ticket, service: secure_root_url))
44+
request = Net::HTTP.new(uri.host, uri.port)
45+
request.use_ssl = true
46+
request.verify_mode = OpenSSL::SSL::VERIFY_NONE
47+
response = request.get(uri.to_s)
48+
@resp = response.body
49+
@xml = Nokogiri::XML(@resp)
50+
@cas_user = @xml.xpath('/cas:serviceResponse/cas:authenticationSuccess/cas:user').text
51+
rescue
52+
@cas_user ||= ''
53+
end
54+
end
5055
end

‎app/helpers/sessions_helper.rb‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def current_user
2424
def signed_in_user
2525
unless signed_in?
2626
store_location
27-
redirect_to signin_url
27+
redirect_to signin_url(ticket: params[:ticket])
2828
end
2929
end
3030

@@ -37,11 +37,16 @@ def sign_out
3737
end
3838

3939
def store_location
40+
return if session[:return_to].present?
4041
session[:return_to] = request.url if request.get?
4142
end
4243

43-
def redirect_back_or_to(default=root_url)
44+
def redirect_back_or_to(default = secure_root_url)
4445
redirect_to(session[:return_to] || default)
4546
session.delete(:return_to)
4647
end
48+
49+
def secure_root_url
50+
root_url(protocol: :https)
51+
end
4752
end

‎config/config.yml‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1+
auth: &auth
2+
cas_host: https://idp-stg.login.iu.edu
3+
cas_login_url: /idp/profile/cas/login
4+
cas_validate_url: /idp/profile/cas/serviceValidate
5+
cas_logout_url: /idp/profile/cas/logout
6+
cas_callback_url: /users/auth/cas/callback
7+
18
development:
9+
auth:
10+
<<: *auth
211
filmdb_update_url: 'http://sycamore.dlib.indiana.edu:8527/services/update_batch/'
312

413
test:
14+
auth:
15+
<<: *auth
516
filmdb_update_url: 'http://sycamore.dlib.indiana.edu:8529/services/update_batch/'
617

718
production:
19+
auth:
20+
<<: *auth
21+
cas_host: https://idp.login.iu.edu
822
filmdb_update_url: 'http://sycamore.dlib.indiana.edu:8528/services/update_batch/'
9-

‎spec/controllers/sessions_controller_spec.rb‎

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,119 @@
11
describe SessionsController do
22
before(:each) { request.env['HTTP_REFERER'] = 'source_page' }
3+
let(:success) {
4+
'<?xml version="1.0" encoding="UTF-8"?>
5+
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
6+
<cas:authenticationSuccess>
7+
<cas:user>web_admin</cas:user>
8+
</cas:authenticationSuccess>
9+
</cas:serviceResponse>' }
10+
let(:failure) {
11+
'<?xml version="1.0" encoding="UTF-8"?>
12+
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
13+
<cas:authenticationFailure code=''INVALID_TICKET''>
14+
E_TICKET_EXPIRED
15+
</cas:authenticationFailure>
16+
</cas:serviceResponse>' }
17+
let(:secure_root_url) { root_url(protocol: :https) }
318

4-
describe "#cas_reg" do
5-
it "returns a cas-reg URL" do
6-
expect(SessionsController.new.cas_reg).to match /https.*cas-reg/
7-
end
8-
end
9-
10-
describe "#cas" do
11-
it "returns a cas URL" do
12-
expect(SessionsController.new.cas_reg).to match /https.*cas/
19+
describe "url helpers" do
20+
describe "#cas" do
21+
context "with no arguments" do
22+
it "returns a cas service root URL" do
23+
expect(SessionsController.new.send(:cas_url)).to match /https.*login/
24+
end
25+
end
26+
context "with invalid action" do
27+
it "returns a cas service root URL" do
28+
expect(SessionsController.new.send(:cas_url, :foo)).to eq SessionsController.new.send(:cas_url)
29+
end
30+
end
31+
context "with :logout" do
32+
it "returns a cas service logout URL" do
33+
expect(SessionsController.new.send(:cas_url, :logout)).to match /https.*login.*logout/
34+
end
35+
end
36+
context "with :login" do
37+
it "returns a cas service login URL" do
38+
expect(SessionsController.new.send(:cas_url, :login, service: 'foo')).to match /https.*login.*login.*foo/
39+
end
40+
end
41+
context "with :validate" do
42+
it "returns a cas service login URL" do
43+
expect(SessionsController.new.send(:cas_url, :validate, ticket: 'foo', service: 'bar')).to match /https.*login.*serviceValidate.*foo.*bar/
44+
end
45+
end
1346
end
1447
end
1548

1649
describe "#new" do
1750
before(:each) do
18-
stub_request(:get, /cas.iu.edu/).
51+
stub_request(:get, /idp-stg.login.iu.edu/).
1952
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
20-
to_return(status: 200, body: "yes", headers: {})
53+
to_return(status: 200, body: success, headers: {})
2154
end
2255
before(:each) { get :new }
23-
let(:cas) { "https://cas.iu.edu" }
2456
it "redirects to cas login" do
25-
expect(response).to redirect_to "#{cas}/cas/login?cassvc=ANY&casurl=#{root_url}sessions/validate_login"
57+
expect(response).to redirect_to SessionsController.new.send(:cas_url, :login, service: secure_root_url)
2658
end
2759
end
2860
describe "#validate_login" do
29-
context "with invalid casticket" do
61+
context "with invalid ticket" do
3062
before(:each) do
31-
stub_request(:get, /cas.iu.edu/).
63+
stub_request(:get, /idp.*login.iu.edu/).
3264
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
33-
to_return(status: 200, body: "no", headers: {})
65+
to_return(status: 200, body: failure, headers: {})
3466
end
35-
before(:each) { get :validate_login, casticket: casticket }
36-
let(:casticket) { 'foo' }
37-
it "assigns @casticket" do
38-
expect(assigns(:casticket)).to eq casticket
67+
before(:each) { get :validate_login, ticket: cas_ticket }
68+
let(:cas_ticket) { 'foo' }
69+
it "assigns @cas_ticket" do
70+
expect(assigns(:cas_ticket)).to eq cas_ticket
3971
end
40-
it "assigns @resp=no" do
41-
expect(assigns(:resp)).to match /^no/
72+
it "assigns @cas_user blank" do
73+
expect(assigns(:cas_user)).to be_blank
4274
end
4375
it "redirects to denial page" do
44-
expect(response).to redirect_to "#{root_url}denied.html"
76+
expect(response).to redirect_to "#{secure_root_url}denied.html"
4577
end
4678
end
47-
context "with valid casticket" do
79+
context "with invalid response" do
4880
before(:each) do
49-
stub_request(:get, /cas.iu.edu/).
81+
stub_request(:get, /idp.*login.iu.edu/).
5082
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
51-
to_return(status: 200, body: "yes--web_admin--", headers: {})
83+
to_return(status: 200, body: 'non-parsing response', headers: {})
84+
end
85+
before(:each) { get :validate_login, ticket: cas_ticket }
86+
let(:cas_ticket) { 'foo' }
87+
it "assigns @cas_ticket" do
88+
expect(assigns(:cas_ticket)).to eq cas_ticket
89+
end
90+
it "assigns @cas_user blank" do
91+
expect(assigns(:cas_user)).to be_blank
92+
end
93+
it "redirects to denial page" do
94+
expect(response).to redirect_to "#{secure_root_url}denied.html"
95+
end
96+
end
97+
context "with valid ticket" do
98+
before(:each) do
99+
stub_request(:get, /idp.*login.iu.edu/).
100+
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
101+
to_return(status: 200, body: success, headers: {})
102+
end
103+
before(:each) { get :validate_login, ticket: cas_ticket }
104+
after(:each) do
105+
sign_out
106+
Thread.current[:current_username] = nil
52107
end
53-
before(:each) { get :validate_login, casticket: casticket }
54-
let(:casticket) { 'valid' }
55-
it "assigns @casticket" do
56-
expect(assigns(:casticket)).to eq casticket
108+
let(:cas_ticket) { 'valid' }
109+
it "assigns @cas_ticket" do
110+
expect(assigns(:cas_ticket)).to eq cas_ticket
57111
end
58-
it "assigns @resp=yes" do
59-
expect(assigns(:resp)).to match /^yes/
112+
it "assigns @cas_user" do
113+
expect(assigns(:cas_user)).not_to be_blank
60114
end
61-
it "redirects to root_url" do
62-
expect(response).to redirect_to root_url
115+
it "redirects to secure_root_url" do
116+
expect(response).to redirect_to secure_root_url
63117
end
64118
end
65119
end
@@ -72,9 +126,9 @@
72126
destroy_session
73127
expect(session[:username]).to be_nil
74128
end
75-
it "redirects to 'https://cas.iu.edu/cas/logout'" do
129+
it "redirects to logout service'" do
76130
destroy_session
77-
expect(response).to redirect_to 'https://cas.iu.edu/cas/logout'
131+
expect(response).to redirect_to SessionsController.new.send(:cas_url, :logout)
78132
end
79133
end
80134

‎spec/helpers/sessions_helper_spec.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
expect(session[:return_to]).to eq 'http://test.host'
7272
end
7373
end
74-
describe "#redirect_back_or_to(default=root_url)" do
74+
describe "#redirect_back_or_to(default = secure_root_url)" do
7575
context "with a session[:return_to]" do
7676
before(:each) { session[:return_to] = 'http://test.host' }
7777
skip "cannot directly test redirect_to in helper test"

‎spec/models/user_spec.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@
9595
end
9696

9797
describe ".current_username=" do
98+
after(:each) { Thread.current[:current_username] = nil }
9899
it "sets Thread.current[:current_username]" do
99100
expect(Thread.current[:current_username]).to be_nil
100101
User.current_username = "test_user"
101102
expect(Thread.current[:current_username]).to eq "test_user"
102-
Thread.current[:current_username] = nil
103103
end
104104
end
105105

0 commit comments

Comments
 (0)