rack-cas 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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