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 +4 -4
- data/README.md +3 -3
- data/lib/rack-cas/configuration.rb +1 -1
- data/lib/rack-cas/saml_validation_response.rb +106 -0
- data/lib/rack-cas/server.rb +11 -1
- data/lib/rack-cas/version.rb +1 -1
- data/lib/rack/cas.rb +1 -1
- metadata +3 -5
- data/lib/rack-cas/session_store/mongo.rb +0 -45
- data/lib/rack-cas/session_store/rack/mongo.rb +0 -10
- data/lib/rack-cas/session_store/rails/mongo.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38012fd82aee3a253f981902a280b0b7ec6d04e5
|
4
|
+
data.tar.gz: 3cbf759de026aca104498d87770a12dd0895b03d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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
|
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
|
data/lib/rack-cas/server.rb
CHANGED
@@ -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
|
-
|
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)
|
data/lib/rack-cas/version.rb
CHANGED
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.
|
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
|
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
|