rack-cas 0.10.1 → 0.11.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e30e5b118a618b8b272d36176d0297a3b6bb9ce9
4
- data.tar.gz: 69b1b0c2de4fdb69220eaee104766eae66897b85
3
+ metadata.gz: 38012fd82aee3a253f981902a280b0b7ec6d04e5
4
+ data.tar.gz: 3cbf759de026aca104498d87770a12dd0895b03d
5
5
  SHA512:
6
- metadata.gz: f85843bf2c05234cf863b2dd5c7653059deb871f76d4bfb6b147fce28731c150fa4f7145526a77e89af9bb75111d6c8c00685e2f592a319b86c3347b5eeb6944
7
- data.tar.gz: 18101042feca858fb47f224d4887026d6a5cebbc12dd8a300c2ce2dcf92de2df4e118d017208517bdc19472e0e096f5d9f997e4f7264b69f38a58065924d40cb
6
+ metadata.gz: e1876204036636478a1bf8d46bceaf3f99a7e83751ab4bdbfdb3aa483312eaa1755aefc50e7731687fdf2c24f9fea023f12c073b6c2eb70a5292386d81789257
7
+ data.tar.gz: a0a8e8f896424d1ec98d4941f9698c8431269ba362372556b316e50861526ea1abb6484afd1fdc2f85087b9f9f9110715aa3d8510f0bd98eba3b2a075dd3f011
data/README.md CHANGED
@@ -38,7 +38,7 @@ If the the server URL depends on your environment, you can define it in the acco
38
38
 
39
39
  ### Single Logout ###
40
40
 
41
- If you wish to enable [single logout](http://jasig.github.io/cas/4.0.0/installation/Logout-Single-Signout.html) you'll need to modify your configuration as below.
41
+ If you wish to enable [single logout](http://jasig.github.io/cas/4.0.x/installation/Logout-Single-Signout.html) you'll need to modify your configuration as below.
42
42
 
43
43
  #### Active Record ####
44
44
 
@@ -50,7 +50,7 @@ config.rack_cas.session_store = RackCAS::ActiveRecordStore
50
50
  Edit your `config/initializers/session_store.rb` file with the following:
51
51
  ```ruby
52
52
  require 'rack-cas/session_store/rails/active_record'
53
- YourApp::Application.config.session_store :rack_cas_active_record_store
53
+ YourApp::Application.config.session_store ActionDispatch::Session::RackCasActiveRecordStore
54
54
  ```
55
55
  Run:
56
56
  ```ruby
@@ -67,7 +67,7 @@ config.rack_cas.session_store = RackCAS::MongoidStore
67
67
  Edit your `config/initializers/session_store.rb` file with the following:
68
68
  ```ruby
69
69
  require 'rack-cas/session_store/rails/mongoid'
70
- YourApp::Application.config.session_store :rack_cas_mongoid_store
70
+ YourApp::Application.config.session_store ActionDispatch::Session::RackCasMongoidStore
71
71
  ```
72
72
  Sinatra and Other Rack-Compatible Frameworks
73
73
  --------------------------------------------
@@ -1,6 +1,6 @@
1
1
  module RackCAS
2
2
  class Configuration
3
- SETTINGS = [:server_url, :session_store, :exclude_path, :exclude_paths, :extra_attributes_filter, :verify_ssl_cert, :renew]
3
+ SETTINGS = [:server_url, :session_store, :exclude_path, :exclude_paths, :extra_attributes_filter, :verify_ssl_cert, :renew, :use_saml_validation]
4
4
 
5
5
  SETTINGS.each do |setting|
6
6
  attr_accessor setting
@@ -0,0 +1,106 @@
1
+ module RackCAS
2
+ class SAMLValidationResponse
3
+ class AuthenticationFailure < StandardError; end
4
+ class TicketInvalidError < AuthenticationFailure; end
5
+
6
+ REQUEST_HEADERS = {
7
+ 'Accept' => '*/*',
8
+ 'Content-Type' => 'application/soap+xml; charset=utf-8'
9
+ }
10
+
11
+ def initialize(url, ticket)
12
+ @url = URL.parse(url)
13
+ @ticket = ticket
14
+ end
15
+
16
+ def user
17
+ if success?
18
+ xml.at('//Response/Assertion/AuthenticationStatement/Subject/NameIdentifier').text
19
+ else
20
+ raise AuthenticationFailure, failure_message
21
+ end
22
+ end
23
+
24
+ def extra_attributes
25
+ attrs = {}
26
+
27
+ raise AuthenticationFailure, failure_message unless success?
28
+
29
+ xml.at('//Response/Assertion/AttributeStatement').children.each do |node|
30
+ key = node.at('@AttributeName')
31
+
32
+ if key
33
+ values = node.xpath('AttributeValue').map { |n| n.text }
34
+
35
+ values = values.first if values.size == 1
36
+
37
+ attrs[key.text] = values
38
+ end
39
+ end
40
+
41
+ attrs
42
+ end
43
+
44
+ protected
45
+
46
+ def success?
47
+ @success ||= xml.at('//Response/Status/StatusCode/@Value').text == 'saml1p:Success'
48
+ end
49
+
50
+ def authentication_failure
51
+ @authentication_failure ||= !@success
52
+ end
53
+
54
+ def failure_message
55
+ if authentication_failure
56
+ xml.at('//Response/Status/StatusMessage').text.strip
57
+ end
58
+ end
59
+
60
+ def response
61
+ require 'net/http'
62
+ return @response unless @response.nil?
63
+
64
+ http = Net::HTTP.new(@url.host, @url.inferred_port)
65
+
66
+ if @url.scheme == 'https'
67
+ http.use_ssl = true
68
+ http.verify_mode = RackCAS.config.verify_ssl_cert? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
69
+ end
70
+
71
+ now = Time.now
72
+
73
+ data = %Q~<?xml version='1.0'?>
74
+ <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
75
+ <SOAP-ENV:Header/>
76
+ <SOAP-ENV:Body>
77
+ <samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" MajorVersion="1" MinorVersion="1" RequestID="_#{ip_address}.#{now.to_i}" IssueInstant="#{now.strftime("%FT%TZ")}">
78
+ <samlp:AssertionArtifact>#{@ticket}</samlp:AssertionArtifact>
79
+ </samlp:Request>
80
+ </SOAP-ENV:Body>
81
+ </SOAP-ENV:Envelope>~
82
+
83
+ @response = http.post(@url.request_uri, data, REQUEST_HEADERS)
84
+ end
85
+
86
+ def xml
87
+ return @xml unless @xml.nil?
88
+
89
+ @xml = Nokogiri::XML(response.body).remove_namespaces!
90
+ end
91
+
92
+ def ip_address
93
+ require 'socket'
94
+
95
+ return @ip_address unless @ip_address.nil?
96
+
97
+ begin
98
+ @ip_address = Socket.ip_address_list.detect{ |intf|
99
+ intf.ipv4? and !intf.ipv4_loopback? and !intf.ipv4_multicast? and !intf.ipv4_private?
100
+ }.ip_address
101
+ rescue
102
+ @ip_address = '127.0.0.1'
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,4 +1,5 @@
1
1
  require 'rack-cas/url'
2
+ require 'rack-cas/saml_validation_response'
2
3
  require 'rack-cas/service_validation_response'
3
4
 
4
5
  module RackCAS
@@ -23,12 +24,21 @@ module RackCAS
23
24
  end
24
25
 
25
26
  def validate_service(service_url, ticket)
26
- response = ServiceValidationResponse.new validate_service_url(service_url, ticket)
27
+ unless RackCAS.config.use_saml_validation?
28
+ response = ServiceValidationResponse.new validate_service_url(service_url, ticket)
29
+ else
30
+ response = SAMLValidationResponse.new saml_validate_url(service_url), ticket
31
+ end
27
32
  [response.user, response.extra_attributes]
28
33
  end
29
34
 
30
35
  protected
31
36
 
37
+ def saml_validate_url(service_url)
38
+ service_url = URL.parse(service_url).remove_param('ticket').to_s
39
+ @url.dup.append_path('samlValidate').add_params(TARGET: service_url)
40
+ end
41
+
32
42
  def validate_service_url(service_url, ticket)
33
43
  service_url = URL.parse(service_url).remove_param('ticket').to_s
34
44
  @url.dup.append_path('serviceValidate').add_params(service: service_url, ticket: ticket)
@@ -1,3 +1,3 @@
1
1
  module RackCAS
2
- VERSION = '0.10.1'
2
+ VERSION = '0.11.0'
3
3
  end
data/lib/rack/cas.rb CHANGED
@@ -25,7 +25,7 @@ class Rack::CAS
25
25
 
26
26
  begin
27
27
  user, extra_attrs = get_user(request.url, cas_request.ticket)
28
- rescue RackCAS::ServiceValidationResponse::TicketInvalidError
28
+ rescue RackCAS::ServiceValidationResponse::TicketInvalidError, RackCAS::SAMLValidationResponse::TicketInvalidError
29
29
  log env, 'rack-cas: Invalid ticket. Redirecting to CAS login.'
30
30
 
31
31
  return redirect_to server.login_url(cas_request.service_url).to_s
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-cas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Crownoble
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-18 00:00:00.000000000 Z
11
+ date: 2015-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -122,15 +122,13 @@ files:
122
122
  - lib/rack-cas/cas_request.rb
123
123
  - lib/rack-cas/configuration.rb
124
124
  - lib/rack-cas/railtie.rb
125
+ - lib/rack-cas/saml_validation_response.rb
125
126
  - lib/rack-cas/server.rb
126
127
  - lib/rack-cas/service_validation_response.rb
127
128
  - lib/rack-cas/session_store/active_record.rb
128
- - lib/rack-cas/session_store/mongo.rb
129
129
  - lib/rack-cas/session_store/mongoid.rb
130
- - lib/rack-cas/session_store/rack/mongo.rb
131
130
  - lib/rack-cas/session_store/rack/mongoid.rb
132
131
  - lib/rack-cas/session_store/rails/active_record.rb
133
- - lib/rack-cas/session_store/rails/mongo.rb
134
132
  - lib/rack-cas/session_store/rails/mongoid.rb
135
133
  - lib/rack-cas/url.rb
136
134
  - lib/rack-cas/version.rb
@@ -1,45 +0,0 @@
1
- module RackCAS
2
- module MongoStore
3
- def collection
4
- @collection
5
- end
6
-
7
- def initialize(app, options = {})
8
- require 'mongo'
9
-
10
- unless options[:collection]
11
- raise "To avoid creating multiple connections to MongoDB, " +
12
- "the Mongo Session Store will not create it's own connection " +
13
- "to MongoDB - you must pass in a collection with the :collection option"
14
- end
15
-
16
- @collection = options[:collection].respond_to?(:call) ? options[:collection].call : options[:collection]
17
-
18
- super
19
- end
20
-
21
- private
22
- def get_session(env, sid)
23
- sid ||= generate_sid
24
- session = collection.find(_id: sid).first || {}
25
- [sid, unpack(session['data'])]
26
- end
27
-
28
- def set_session(env, sid, session_data, options = {})
29
- sid ||= generate_sid
30
- collection.update({'_id' => sid},
31
- {'_id' => sid, 'data' => pack(session_data), 'updated_at' => Time.now},
32
- upsert: true)
33
- sid # TODO: return boolean, right?
34
- end
35
-
36
- def pack(data)
37
- [Marshal.dump(data)].pack('m*')
38
- end
39
-
40
- def unpack(packed)
41
- return nil unless packed
42
- Marshal.load(packed.unpack('m*').first)
43
- end
44
- end
45
- end
@@ -1,10 +0,0 @@
1
- require 'rack-cas/session_store/mongo'
2
- require 'rack/session/abstract/id'
3
-
4
- module Rack
5
- module Session
6
- class RackCASMongoStore < Rack::Session::Abstract::ID
7
- include RackCAS::MongoStore
8
- end
9
- end
10
- end
@@ -1,10 +0,0 @@
1
- require 'rack-cas/session_store/mongo'
2
- require 'action_dispatch/middleware/session/abstract_store'
3
-
4
- module ActionDispatch
5
- module Session
6
- class RackCasMongoStore < AbstractStore
7
- include RackCAS::MongoStore
8
- end
9
- end
10
- end