authpds 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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