authpds 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.rdoc +1 -3
  2. data/Rakefile +1 -2
  3. data/lib/authpds.rb +4 -14
  4. data/lib/authpds/acts_as_authentic.rb +3 -60
  5. data/lib/authpds/acts_as_authentic/core_attributes.rb +24 -0
  6. data/lib/authpds/acts_as_authentic/expiration.rb +19 -0
  7. data/lib/authpds/acts_as_authentic/institutions_attributes.rb +34 -0
  8. data/lib/authpds/controllers/authpds_controller.rb +3 -61
  9. data/lib/authpds/controllers/authpds_controller/core_attributes.rb +24 -0
  10. data/lib/authpds/controllers/authpds_controller/institution_attributes.rb +54 -0
  11. data/lib/authpds/controllers/authpds_controller/url_handling.rb +18 -0
  12. data/lib/authpds/controllers/authpds_sessions_controller.rb +0 -1
  13. data/lib/authpds/session.rb +15 -247
  14. data/lib/authpds/session/authentication.rb +24 -0
  15. data/lib/authpds/session/authlogic_callbacks.rb +12 -0
  16. data/lib/authpds/session/authorization.rb +16 -0
  17. data/lib/authpds/session/callbacks.rb +30 -0
  18. data/lib/authpds/session/config.rb +60 -0
  19. data/lib/authpds/session/core_attributes.rb +45 -0
  20. data/lib/authpds/session/exception_handling.rb +22 -0
  21. data/lib/authpds/session/institution_attributes.rb +15 -0
  22. data/lib/authpds/session/pds_user.rb +17 -0
  23. data/lib/authpds/session/record.rb +32 -0
  24. data/lib/authpds/session/url_handling.rb +55 -0
  25. data/lib/authpds/version.rb +1 -1
  26. data/test/{unit/authpds_controller_test.rb → authpds_controller_test.rb} +19 -11
  27. data/test/{unit/authpds_user_sessions_controller_test.rb → authpds_user_sessions_controller_test.rb} +3 -1
  28. data/test/fixtures/users.yml +2 -2
  29. data/test/pds_test.rb +83 -0
  30. data/test/support/config/institutions.yml +4 -4
  31. data/test/test_helper.rb +10 -4
  32. data/test/{unit/user_session_test.rb → user_session_test.rb} +34 -28
  33. data/test/{unit/user_test.rb → user_test.rb} +2 -2
  34. data/test/vcr_cassettes/bor_info_valid_newschool.yml +35 -0
  35. data/test/vcr_cassettes/bor_info_valid_nyu.yml +40 -0
  36. data/test/vcr_cassettes/get_attribute_authenticate.yml +36 -0
  37. data/test/vcr_cassettes/get_attribute_bor_id.yml +32 -0
  38. data/test/vcr_cassettes/get_attribute_bor_info.yml +40 -0
  39. data/test/vcr_cassettes/get_attribute_bor_verification.yml +32 -0
  40. data/test/vcr_cassettes/get_attribute_invalid_bor_info.yml +33 -0
  41. data/test/vcr_cassettes/invalid_bor_info.yml +33 -0
  42. data/test/vcr_cassettes/nyu.yml +40 -0
  43. metadata +104 -21
  44. data/test/unit/pds_test.rb +0 -62
@@ -0,0 +1,24 @@
1
+ module Authpds
2
+ module Session
3
+ module Authentication
4
+ def authenticated?
5
+ authenticate
6
+ end
7
+ protected :authenticated?
8
+
9
+ def authenticate
10
+ # Don't authenticate if the system is inaccessible.
11
+ # If the application session id is nil, skip this check.
12
+ return false if controller.cookies["#{calling_system}_inaccessible".to_sym] == session_id unless session_id.nil?
13
+ # If PDS session already established, authenticate
14
+ return true unless pds_user.nil?
15
+ # Establish a PDS session if the user logged in via an alternative SSO mechanism and this isn't being called after login
16
+ controller.redirect_to sso_url({
17
+ :return_url => controller.request.url }) if valid_sso_session? unless controller.params["action"] =="validate" or controller.performed?
18
+ # Otherwise, do not authenticate
19
+ return false
20
+ end
21
+ protected :authenticate
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ module Authpds
2
+ module Session
3
+ module AuthlogicCallbacks
4
+ # Callback method from Authlogic.
5
+ # Called while trying to persist the session.
6
+ def persist_session
7
+ destroy unless (authenticated? and authorized?) or anonymous?
8
+ end
9
+ protected :persist_session
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module Authpds
2
+ module Session
3
+ module Authorization
4
+ def authorized?
5
+ # Set all the information that is needed to make an authorization decision
6
+ set_record and return authorize
7
+ end
8
+ protected :authorized?
9
+
10
+ def authorize
11
+ # If PDS user is not nil (PDS session already established), authorize
12
+ !pds_user.nil? && additional_authorization
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ module Authpds
2
+ module Session
3
+ module Callbacks
4
+ # Hook for more complicated logic to determine PDS user record identifier
5
+ def pds_record_identifier
6
+ @pds_record_identifier ||= self.class.pds_record_identifier
7
+ end
8
+
9
+ # Hook to determine if we should set up an SSO session
10
+ def valid_sso_session?
11
+ return false
12
+ end
13
+
14
+ # Hook to provide additional authorization requirements
15
+ def additional_authorization
16
+ return true
17
+ end
18
+
19
+ # Hook to add additional user attributes.
20
+ def additional_attributes
21
+ {}
22
+ end
23
+
24
+ # Hook to update expiration date if necessary
25
+ def expiration_date
26
+ 1.week.ago
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,60 @@
1
+ module Authpds
2
+ module Session
3
+ module Config
4
+ # Base pds url
5
+ def pds_url(value = nil)
6
+ rw_config(:pds_url, value)
7
+ end
8
+ alias_method :pds_url=, :pds_url
9
+
10
+ # Name of the system
11
+ def calling_system(value = nil)
12
+ rw_config(:calling_system, value, "authpds")
13
+ end
14
+ alias_method :calling_system=, :calling_system
15
+
16
+ # Does the system allow anonymous access?
17
+ def anonymous(value = nil)
18
+ rw_config(:anonymous, value, true)
19
+ end
20
+ alias_method :anonymous=, :anonymous
21
+
22
+ # Mapping of PDS attributes
23
+ def pds_attributes(value = nil)
24
+ value.each_value { |pds_attr| pds_attr.gsub!("-", "_") } unless value.nil?
25
+ rw_config(:pds_attributes, value, {:email => "email", :firstname => "name", :lastname => "name", :primary_institution => "institute" })
26
+ end
27
+ alias_method :pds_attributes=, :pds_attributes
28
+
29
+ # Custom redirect logout url
30
+ def redirect_logout_url(value = nil)
31
+ rw_config(:redirect_logout_url, value, "")
32
+ end
33
+ alias_method :redirect_logout_url=, :redirect_logout_url
34
+
35
+ # Custom url to redirect to in case of system outage
36
+ def login_inaccessible_url(value = nil)
37
+ rw_config(:login_inaccessible_url, value, "")
38
+ end
39
+ alias_method :redirect_logout_url=, :redirect_logout_url
40
+
41
+ # PDS user method to call to identify record
42
+ def pds_record_identifier(value = nil)
43
+ rw_config(:pds_record_identifier, value, :id)
44
+ end
45
+ alias_method :pds_record_identifier=, :pds_record_identifier
46
+
47
+ # Querystring parameter key for the institution value
48
+ def institution_param_key(value = nil)
49
+ rw_config(:institution_param_key, value, "institute")
50
+ end
51
+ alias_method :institution_param_key=, :institution_param_key
52
+
53
+ # URL name for validation action
54
+ def validate_url_name(value = nil)
55
+ rw_config(:validate_url_name, value, "validate_url")
56
+ end
57
+ alias_method :validate_url_name=, :validate_url_name
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,45 @@
1
+ module Authpds
2
+ module Session
3
+ module CoreAttributes
4
+ def anonymous
5
+ @anonymous ||=self.class.anonymous
6
+ end
7
+ alias anonymous? anonymous
8
+
9
+ def calling_system
10
+ @calling_system ||= self.class.calling_system
11
+ end
12
+
13
+ def login_inaccessible_url
14
+ @login_inaccessible_url ||= self.class.login_inaccessible_url
15
+ end
16
+
17
+ def pds_attributes
18
+ @pds_attributes ||= self.class.pds_attributes
19
+ end
20
+
21
+ def pds_url
22
+ @pds_url ||= self.class.pds_url
23
+ end
24
+
25
+ def redirect_logout_url
26
+ @redirect_logout_url ||= self.class.redirect_logout_url
27
+ end
28
+
29
+ def validate_url_name
30
+ @validate_url_name ||= self.class.validate_url_name
31
+ end
32
+
33
+ def pds_handle
34
+ @pds_handle ||= (controller.cookies[:PDS_HANDLE] || controller.params[:pds_handle])
35
+ end
36
+
37
+ def session_id
38
+ @session_id ||=
39
+ (controller.session.respond_to?(:session_id)) ?
40
+ (controller.session.session_id) ?
41
+ controller.session.session_id : controller.session[:session_id] : controller.session[:session_id]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,22 @@
1
+ module Authpds
2
+ module Session
3
+ module ExceptionHandling
4
+ def handle_login_exception(error)
5
+ # Set a cookie saying that we've got some invalid stuff going on
6
+ # in this session. Either PDS is screwy, OpenSSO is screwy, or both.
7
+ # Either way, we want to skip logging in since it's problematic (if anonymous).
8
+ controller.cookies["#{calling_system}_inaccessible".to_sym] = {
9
+ :value => session_id,
10
+ :path => "/" } if anonymous?
11
+ # If anonymous access isn't allowed, we can't rightfully set the cookie.
12
+ # We probably should send to a system down page.
13
+ controller.redirect_to(login_inaccessible_url)
14
+ alert_the_authorities error
15
+ end
16
+
17
+ def alert_the_authorities(error)
18
+ controller.logger.error("Error in #{self.class}. Something is amiss with PDS authentication.\n#{error}\n#{error.backtrace.inspect}}")
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Authpds
2
+ module Session
3
+ module InstitutionAttributes
4
+ def institution_attributes
5
+ @institution_attributes ||=
6
+ (controller.current_primary_institution.nil? or controller.current_primary_institution.auth.nil?) ?
7
+ {} : controller.current_primary_institution.auth
8
+ end
9
+
10
+ def insitution_code
11
+ @institution_code ||= institution_attributes["code"]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Authpds
2
+ module Session
3
+ module PdsUser
4
+ def pds_user
5
+ begin
6
+ @pds_user ||= Authpds::Exlibris::Pds::BorInfo.new(pds_url, calling_system, pds_handle) unless pds_handle.nil?
7
+ return @pds_user unless @pds_user.nil? or @pds_user.error
8
+ rescue Exception => e
9
+ # Delete the PDS_HANDLE, since this isn't working.
10
+ # controller.cookies.delete(:PDS_HANDLE) unless pds_handle.nil?
11
+ handle_login_exception e
12
+ return nil
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ module Authpds
2
+ module Session
3
+ module Record
4
+ # Get the record associated with this PDS user.
5
+ def get_record(login)
6
+ record = (klass.find_by_smart_case_login_field(login) || klass.new(login_field => login))
7
+ end
8
+
9
+ # Set the record information associated with this PDS user.
10
+ def set_record
11
+ self.attempted_record = get_record(pds_user.send(pds_record_identifier))
12
+ self.attempted_record.expiration_date = expiration_date
13
+ # Do this part only if user data has expired.
14
+ reset_record attempted_record if self.attempted_record.expired?
15
+ self.attempted_record.user_attributes= additional_attributes
16
+ end
17
+
18
+ # Reset expired data
19
+ def reset_record(attempted_record)
20
+ pds_attributes.each do |record_attr, pds_attr|
21
+ attempted_record.send("#{record_attr}=".to_sym,
22
+ pds_user.send(pds_attr.to_sym)) if self.attempted_record.respond_to?("#{record_attr}=".to_sym)
23
+ end
24
+ pds_user.class.public_instance_methods(false).each do |pds_attr_reader|
25
+ attempted_record.user_attributes = {
26
+ pds_attr_reader.to_sym => pds_user.send(pds_attr_reader.to_sym) }
27
+ end
28
+ end
29
+ private :reset_record
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,55 @@
1
+ module Authpds
2
+ module Session
3
+ module UrlHandling
4
+ require "cgi"
5
+
6
+ # URL to redirect to for login.
7
+ # Preceded by :before_login
8
+ def login_url(params={})
9
+ auth_pds_login_url "load-login", params
10
+ end
11
+
12
+ # URL to redirect to in the case of establishing a SSO session.
13
+ def sso_url(params={})
14
+ auth_pds_login_url "sso", params
15
+ end
16
+
17
+ # URL to redirect to after logout.
18
+ def logout_url(params={})
19
+ auth_pds_url "logout", user_session_redirect_url(redirect_logout_url), params
20
+ end
21
+
22
+ def auth_pds_login_url(func, params)
23
+ auth_pds_url func, validate_url(params), :institute => insitution_code, :calling_system => calling_system
24
+ end
25
+ protected :auth_pds_login_url
26
+
27
+ def auth_pds_url(func, url, params)
28
+ auth_pds_url = "#{pds_url}/pds?func=#{func}"
29
+ params.each_pair do |key, value|
30
+ auth_pds_url << "&#{key}=#{CGI::escape(value)}" unless key.nil? or value.nil?
31
+ end
32
+ auth_pds_url << "&url=#{CGI::escape(url)}"
33
+ end
34
+ private :auth_pds_url
35
+
36
+ def user_session_redirect_url(url)
37
+ controller.user_session_redirect_url(url)
38
+ end
39
+ private :user_session_redirect_url
40
+
41
+ # Returns the URL for validating a UserSession on return from a remote login system.
42
+ def validate_url(params={})
43
+ url = controller.send(validate_url_name, :return_url => user_session_redirect_url(params[:return_url]))
44
+ return url if params.nil? or params.empty?
45
+ url << "?" if url.match('\?').nil?
46
+ params.each do |key, value|
47
+ next if [:controller, :action, :return_url].include?(key)
48
+ url << "&#{calling_system}_#{key}=#{CGI::escape(value)}" unless key.nil? or value.nil?
49
+ end
50
+ url
51
+ end
52
+ private :validate_url
53
+ end
54
+ end
55
+ end
@@ -1,3 +1,3 @@
1
1
  module Authpds
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -16,8 +16,10 @@ class ApplicationControllerTest < ActiveSupport::TestCase
16
16
  test "current_user_session" do
17
17
  assert_nil(controller.current_user_session)
18
18
  controller.cookies[:PDS_HANDLE] = { :value => VALID_PDS_HANDLE_FOR_NYU }
19
- user_session = controller.current_user_session
20
- assert_not_nil(user_session)
19
+ VCR.use_cassette('nyu') do
20
+ user_session = controller.current_user_session
21
+ assert_not_nil(user_session)
22
+ end
21
23
  end
22
24
 
23
25
  test "current_user_nil" do
@@ -27,9 +29,11 @@ class ApplicationControllerTest < ActiveSupport::TestCase
27
29
  test "current_user" do
28
30
  assert_nil(controller.current_user)
29
31
  controller.cookies[:PDS_HANDLE] = { :value => VALID_PDS_HANDLE_FOR_NYU }
30
- user = controller.current_user
31
- assert_not_nil(user)
32
- assert_equal("N12162279", user.username)
32
+ VCR.use_cassette('nyu') do
33
+ user = controller.current_user
34
+ assert_not_nil(user)
35
+ assert_equal("N12162279", user.username)
36
+ end
33
37
  end
34
38
 
35
39
  test "current_primary_institution_nil" do
@@ -44,11 +48,15 @@ class ApplicationControllerTest < ActiveSupport::TestCase
44
48
  end
45
49
 
46
50
  test "current_primary_institution_user" do
47
- assert_nil(controller.current_primary_institution)
48
- Institutions.loadpaths<< "#{File.dirname(__FILE__)}/../support/config"
49
- controller.cookies[:PDS_HANDLE] = { :value => VALID_PDS_HANDLE_FOR_NYU }
50
- assert_equal("N12162279", controller.current_user.username)
51
- assert_equal(Institutions.institutions[:NYU], controller.current_user.primary_institution)
52
- assert_equal(Institutions.institutions[:NYU], controller.current_primary_institution)
51
+ assert_nothing_raised{
52
+ assert_nil(controller.current_primary_institution)
53
+ Institutions.loadpaths<< "#{File.dirname(__FILE__)}/../support/config"
54
+ controller.cookies[:PDS_HANDLE] = { :value => VALID_PDS_HANDLE_FOR_NYU }
55
+ VCR.use_cassette('nyu') do
56
+ assert_equal("N12162279", controller.current_user.username)
57
+ assert_equal(Institutions.institutions[:NYU], controller.current_user.primary_institution)
58
+ assert_equal(Institutions.institutions[:NYU], controller.current_primary_institution)
59
+ end
60
+ }
53
61
  end
54
62
  end
@@ -8,6 +8,8 @@ class UserSessionsControllerTest < ActiveSupport::TestCase
8
8
  end
9
9
 
10
10
  test "current_user_session" do
11
- user_session = controller.current_user_session
11
+ VCR.use_cassette('nyu') do
12
+ user_session = controller.current_user_session
13
+ end
12
14
  end
13
15
  end
@@ -17,7 +17,7 @@ ba36:
17
17
  :nyuidn => "N18158418",
18
18
  :verification => "6EAF453D8B01E5AC27D9",
19
19
  :bor_status => "51",
20
- :aleph_permissions => {} }.to_yaml.inspect %>
20
+ :aleph_permissions => {} }.to_yaml.inspect %>
21
21
  # std5:
22
22
  # password_salt: <%#= salt = Authlogic::Random.hex_token %>
23
23
  # crypted_password: <%#= Authlogic::CryptoProviders::Sha512.encrypt("std5" + salt) %>
@@ -45,5 +45,5 @@ st75:
45
45
  :nyuidn => "N10450419",
46
46
  :verification => "A64C45148D130E78D8AA",
47
47
  :bor_status => "50",
48
- :aleph_permissions => {} }.to_yaml.inspect %>
48
+ :aleph_permissions => {} }.to_yaml.inspect %>
49
49
 
@@ -0,0 +1,83 @@
1
+ require 'test_helper'
2
+
3
+ class PdsTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @pds_url = "https://logindev.library.nyu.edu"
7
+ @calling_system = "authpds"
8
+ @valid_pds_handle_for_nyu = VALID_PDS_HANDLE_FOR_NYU
9
+ @valid_pds_handle_for_newschool = VALID_PDS_HANDLE_FOR_NEWSCHOOL
10
+ @invalid_pds_handle = INVALID_PDS_HANDLE
11
+ @attribute = "bor_info"
12
+ end
13
+
14
+ test "get_attribute_valid" do
15
+ assert_nothing_raised {
16
+ VCR.use_cassette('get_attribute_bor_info') do
17
+ get_attribute = Authpds::Exlibris::Pds::GetAttribute.new(@pds_url, @calling_system, @valid_pds_handle_for_nyu, "bor_info")
18
+ assert_equal("N12162279", get_attribute.response.at("//id").inner_text)
19
+ end
20
+ VCR.use_cassette('get_attribute_bor_verification') do
21
+ get_attribute = Authpds::Exlibris::Pds::GetAttribute.new(@pds_url, @calling_system, @valid_pds_handle_for_nyu, "bor_verification")
22
+ assert_equal("N12162279", get_attribute.response.at("//id").inner_text)
23
+ end
24
+ VCR.use_cassette('get_attribute_bor_id') do
25
+ get_attribute = Authpds::Exlibris::Pds::GetAttribute.new(@pds_url, @calling_system, @valid_pds_handle_for_nyu, "bor_id")
26
+ assert_equal("N12162279", get_attribute.response.at("//id").inner_text)
27
+ end
28
+ VCR.use_cassette('get_attribute_authenticate') do
29
+ get_attribute = Authpds::Exlibris::Pds::GetAttribute.new(@pds_url, @calling_system, @valid_pds_handle_for_nyu, "authenticate")
30
+ assert_equal("N12162279", get_attribute.response.at("//id").inner_text)
31
+ end
32
+ }
33
+ end
34
+
35
+ test "get_attribute_invalid" do
36
+ VCR.use_cassette('get_attribute_invalid_bor_info') do
37
+ get_attribute = Authpds::Exlibris::Pds::GetAttribute.new(@pds_url, @calling_system, @invalid_pds_handle, "bor_info")
38
+ assert_equal("Error User does not exist", get_attribute.error)
39
+ end
40
+ end
41
+
42
+ test "bor_info_valid_nyu" do
43
+ VCR.use_cassette('bor_info_valid_nyu') do
44
+ nyu = Authpds::Exlibris::Pds::BorInfo.new(@pds_url, @calling_system, @valid_pds_handle_for_nyu)
45
+ assert_nothing_raised {
46
+ assert_equal("N12162279", nyu.id)
47
+ assert_equal("N12162279", nyu.nyuidn)
48
+ assert_equal("51", nyu.bor_status)
49
+ assert_equal("CB", nyu.bor_type)
50
+ assert_equal("SCOT THOMAS", nyu.name)
51
+ assert_equal("SCOT THOMAS", nyu.givenname)
52
+ assert_equal("DALTON", nyu.sn)
53
+ assert_equal("Y", nyu.ill_permission)
54
+ assert_equal("GA", nyu.college_code)
55
+ assert_equal("CSCI", nyu.dept_code)
56
+ assert_equal("Information Systems", nyu.major)
57
+ }
58
+ end
59
+ end
60
+
61
+ test "bor_info_valid_newschool" do
62
+ VCR.use_cassette('bor_info_valid_newschool') do
63
+ newschool = Authpds::Exlibris::Pds::BorInfo.new(@pds_url, @calling_system, @valid_pds_handle_for_newschool)
64
+ assert_nothing_raised {
65
+ assert_equal("N00206454", newschool.id)
66
+ assert_equal("N00206454", newschool.nyuidn)
67
+ assert_equal("31", newschool.bor_status)
68
+ assert_equal("0", newschool.bor_type)
69
+ assert_equal("Allen", newschool.name)
70
+ assert_equal("Allen", newschool.givenname)
71
+ assert_equal("Jones", newschool.sn)
72
+ assert_equal("Y", newschool.ill_permission)
73
+ }
74
+ end
75
+ end
76
+
77
+ test "bor_info_invalid" do
78
+ VCR.use_cassette('invalid_bor_info') do
79
+ get_attribute = Authpds::Exlibris::Pds::BorInfo.new(@pds_url, @calling_system, @invalid_pds_handle)
80
+ assert_equal("Error User does not exist", get_attribute.error)
81
+ end
82
+ end
83
+ end