omniauth-cas 0.0.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.
- data/.gitignore +20 -0
- data/.rvmrc +55 -0
- data/.travis.yml +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +33 -0
- data/Rakefile +13 -0
- data/lib/omniauth-cas.rb +1 -0
- data/lib/omniauth/cas.rb +2 -0
- data/lib/omniauth/cas/version.rb +5 -0
- data/lib/omniauth/strategies/cas.rb +174 -0
- data/lib/omniauth/strategies/cas/configuration.rb +23 -0
- data/lib/omniauth/strategies/cas/service_ticket_validator.rb +93 -0
- data/omniauth-cas.gemspec +30 -0
- data/spec/fixtures/cas_failure.xml +4 -0
- data/spec/fixtures/cas_success.xml +14 -0
- data/spec/omniauth/strategies/cas_spec.rb +123 -0
- data/spec/spec_helper.rb +9 -0
- metadata +166 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
|
7
|
+
environment_id="ruby-1.9.2-p290@omniauth-cas"
|
8
|
+
|
9
|
+
#
|
10
|
+
# Uncomment following line if you want options to be set only for given project.
|
11
|
+
#
|
12
|
+
# PROJECT_JRUBY_OPTS=( --1.9 )
|
13
|
+
|
14
|
+
#
|
15
|
+
# First we attempt to load the desired environment directly from the environment
|
16
|
+
# file. This is very fast and efficient compared to running through the entire
|
17
|
+
# CLI and selector. If you want feedback on which environment was used then
|
18
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
19
|
+
#
|
20
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
21
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
22
|
+
then
|
23
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
24
|
+
|
25
|
+
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
|
26
|
+
then
|
27
|
+
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
|
28
|
+
fi
|
29
|
+
else
|
30
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
31
|
+
if ! rvm --create use "$environment_id"
|
32
|
+
then
|
33
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
34
|
+
return 1
|
35
|
+
fi
|
36
|
+
fi
|
37
|
+
|
38
|
+
#
|
39
|
+
# If you use an RVM gemset file to install a list of gems (*.gems), you can have
|
40
|
+
# it be automatically loaded. Uncomment the following and adjust the filename if
|
41
|
+
# necessary.
|
42
|
+
#
|
43
|
+
# filename=".gems"
|
44
|
+
# if [[ -s "$filename" ]]
|
45
|
+
# then
|
46
|
+
# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
|
47
|
+
# fi
|
48
|
+
|
49
|
+
# If you use bundler, this might be useful to you:
|
50
|
+
# if command -v bundle && [[ -s Gemfile ]]
|
51
|
+
# then
|
52
|
+
# bundle install
|
53
|
+
# fi
|
54
|
+
|
55
|
+
|
data/.travis.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm: 1.9.2
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2011 Derek Lindahl and CustomInk, LLC
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# OmniAuth CAS Strategy [](http://travis-ci.org/dlindahl/omniauth-cas)
|
2
|
+
|
3
|
+
A CAS Strategy for OmniAuth.
|
4
|
+
|
5
|
+
I didn't really want to do this, but no one else has, so I might as well give it a stab.
|
6
|
+
|
7
|
+
This is highly experimental, use at your own risk!
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'omniauth-cas'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install omniauth-cas
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
desc 'Default: run specs.'
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
desc "Run specs"
|
9
|
+
RSpec::Core::RakeTask.new
|
10
|
+
|
11
|
+
task :test do
|
12
|
+
fail %q{This application uses RSpec. Try running "rake spec"}
|
13
|
+
end
|
data/lib/omniauth-cas.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "omniauth/cas"
|
data/lib/omniauth/cas.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'omniauth/strategy'
|
2
|
+
require 'addressable/uri'
|
3
|
+
|
4
|
+
module OmniAuth
|
5
|
+
module Strategies
|
6
|
+
class CAS
|
7
|
+
include OmniAuth::Strategy
|
8
|
+
|
9
|
+
autoload :Configuration, 'omniauth/strategies/cas/configuration'
|
10
|
+
autoload :ServiceTicketValidator, 'omniauth/strategies/cas/service_ticket_validator'
|
11
|
+
|
12
|
+
attr_accessor :raw_info
|
13
|
+
alias_method :user_info, :raw_info
|
14
|
+
|
15
|
+
option :name, :cas # TODO: Why do I need to specify this?
|
16
|
+
|
17
|
+
option :host, nil
|
18
|
+
option :port, nil
|
19
|
+
option :ssl, true
|
20
|
+
option :service_validate_url, '/serviceValidate'
|
21
|
+
option :login_url, '/login'
|
22
|
+
option :logout_url, '/logout'
|
23
|
+
option :uid_key, 'user'
|
24
|
+
|
25
|
+
# As required by https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
|
26
|
+
AuthHashSchemaKeys = %w{name email first_name last_name location image phone}
|
27
|
+
info do
|
28
|
+
prune!({
|
29
|
+
:name => raw_info['name'],
|
30
|
+
:email => raw_info['email'],
|
31
|
+
:first_name => raw_info['first_name'],
|
32
|
+
:last_name => raw_info['last_name'],
|
33
|
+
:location => raw_info['location'],
|
34
|
+
:image => raw_info['image'],
|
35
|
+
:phone => raw_info['phone']
|
36
|
+
})
|
37
|
+
end
|
38
|
+
|
39
|
+
extra do
|
40
|
+
prune! raw_info.delete_if{ |k,v| AuthHashSchemaKeys.include?(k) }
|
41
|
+
end
|
42
|
+
|
43
|
+
uid do
|
44
|
+
raw_info[ @options[:uid_key].to_s ]
|
45
|
+
end
|
46
|
+
|
47
|
+
credentials do
|
48
|
+
prune!({
|
49
|
+
:ticket => @ticket
|
50
|
+
})
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize( app, *args, &block )
|
54
|
+
super
|
55
|
+
@configuration = Configuration.new( @options )
|
56
|
+
end
|
57
|
+
|
58
|
+
def callback_phase
|
59
|
+
@ticket = request.params['ticket']
|
60
|
+
|
61
|
+
return fail!(:no_ticket, 'No CAS Ticket') unless @ticket
|
62
|
+
|
63
|
+
self.raw_info = ServiceTicketValidator.new(self, @options, callback_url, @ticket).user_info
|
64
|
+
|
65
|
+
return fail!(:invalid_ticket, 'Invalid CAS Ticket') if raw_info.empty?
|
66
|
+
|
67
|
+
super
|
68
|
+
end
|
69
|
+
|
70
|
+
def request_phase
|
71
|
+
[
|
72
|
+
302,
|
73
|
+
{
|
74
|
+
'Location' => login_url( append_params(callback_url, :url => request.referer) ),
|
75
|
+
'Content-Type' => 'text/plain'
|
76
|
+
},
|
77
|
+
["You are being redirected to CAS for sign-in."]
|
78
|
+
]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Build a CAS host with protocol and port
|
82
|
+
#
|
83
|
+
#
|
84
|
+
def cas_host
|
85
|
+
@host ||= begin
|
86
|
+
host = @options.ssl ? "https" : "http"
|
87
|
+
port = @options.port ? ":#{@options.port}" : ''
|
88
|
+
|
89
|
+
"#{host}://#{@options.host}#{port}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Build a service-validation URL from +service+ and +ticket+.
|
94
|
+
# If +service+ has a ticket param, first remove it. URL-encode
|
95
|
+
# +service+ and add it and the +ticket+ as paraemters to the
|
96
|
+
# CAS serviceValidate URL.
|
97
|
+
#
|
98
|
+
# @param [String] service the service (a.k.a. return-to) URL
|
99
|
+
# @param [String] ticket the ticket to validate
|
100
|
+
#
|
101
|
+
# @return [String] a URL like `http://cas.mycompany.com/serviceValidate?service=...&ticket=...`
|
102
|
+
def service_validate_url(service_url, ticket)
|
103
|
+
service_url = Addressable::URI.parse( service_url )
|
104
|
+
service_url.query_values = service_url.query_values.tap { |qs| qs.delete('ticket') }
|
105
|
+
|
106
|
+
cas_host + append_params(@options.service_validate_url, { :service => service_url.to_s, :ticket => ticket })
|
107
|
+
end
|
108
|
+
|
109
|
+
# Build a CAS login URL from +service+.
|
110
|
+
#
|
111
|
+
# @param [String] service the service (a.k.a. return-to) URL
|
112
|
+
#
|
113
|
+
# @return [String] a URL like `http://cas.mycompany.com/login?service=...`
|
114
|
+
def login_url(service)
|
115
|
+
cas_host + append_params( @options.login_url, { :service => Rack::Utils.unescape(service) })
|
116
|
+
end
|
117
|
+
|
118
|
+
# Adds URL-escaped +parameters+ to +base+.
|
119
|
+
#
|
120
|
+
# @param [String] base the base URL
|
121
|
+
# @param [String] service the service (a.k.a. return-to) URL.
|
122
|
+
#
|
123
|
+
# @return [String] the new joined URL.
|
124
|
+
def append_params(base, params)
|
125
|
+
Addressable::URI.parse(base).tap do |base_uri|
|
126
|
+
base_uri.query_values = (base_uri.query_values || {}).merge( params )
|
127
|
+
end.to_s
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
# Deletes Hash pairs with `nil` values.
|
133
|
+
# From https://github.com/mkdynamic/omniauth-facebook/blob/972ed5e3456bcaed7df1f55efd7c05c216c8f48e/lib/omniauth/strategies/facebook.rb#L122-127
|
134
|
+
def prune!(hash)
|
135
|
+
hash.delete_if do |_, value|
|
136
|
+
prune!(value) if value.is_a?(Hash)
|
137
|
+
value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# def cas_url( path )
|
142
|
+
# "#{cas_protocol}://#{@options.host}#{@options.port}#{path}"
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
# def cas_protocol
|
146
|
+
# @options.ssl ? "https" : "http"
|
147
|
+
# end
|
148
|
+
|
149
|
+
# uid do
|
150
|
+
# ap "UID"
|
151
|
+
# # request.params[options.uid_field.to_s]
|
152
|
+
# end
|
153
|
+
|
154
|
+
# info do
|
155
|
+
# ap "INFO"
|
156
|
+
# # options.fields.inject({}) do |hash, field|
|
157
|
+
# # hash[field] = request.params[field.to_s]
|
158
|
+
# # hash
|
159
|
+
# # end
|
160
|
+
# end
|
161
|
+
|
162
|
+
# extra do
|
163
|
+
# ap "EXTRA"
|
164
|
+
# end
|
165
|
+
|
166
|
+
# credentials do
|
167
|
+
# ap "CREDENTIALS"
|
168
|
+
# end
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
OmniAuth.config.add_camelization 'cas', 'CAS'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'awesome_print'
|
2
|
+
|
3
|
+
module OmniAuth
|
4
|
+
module Strategies
|
5
|
+
class CAS
|
6
|
+
class Configuration
|
7
|
+
|
8
|
+
def initialize( options )
|
9
|
+
@options = options
|
10
|
+
|
11
|
+
validate_cas_setup
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_cas_setup
|
15
|
+
if @options.host.nil? or @options.login_url.nil?
|
16
|
+
raise ArgumentError.new(":host and :login_url MUST be provided")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'awesome_print'
|
5
|
+
|
6
|
+
module OmniAuth
|
7
|
+
module Strategies
|
8
|
+
class CAS
|
9
|
+
class ServiceTicketValidator
|
10
|
+
|
11
|
+
VALIDATION_REQUEST_HEADERS = { 'Accept' => '*/*' }
|
12
|
+
|
13
|
+
# Build a validator from a +configuration+, a
|
14
|
+
# +return_to+ URL, and a +ticket+.
|
15
|
+
#
|
16
|
+
# @param [Hash] options the OmniAuth Strategy options
|
17
|
+
# @param [String] return_to_url the URL of this CAS client service
|
18
|
+
# @param [String] ticket the service ticket to validate
|
19
|
+
def initialize(strategy, options, return_to_url, ticket)
|
20
|
+
@options = options
|
21
|
+
@uri = URI.parse(strategy.service_validate_url(return_to_url, ticket))
|
22
|
+
end
|
23
|
+
|
24
|
+
# Request validation of the ticket from the CAS server's
|
25
|
+
# serviceValidate (CAS 2.0) function.
|
26
|
+
#
|
27
|
+
# Swallows all XML parsing errors (and returns +nil+ in those cases).
|
28
|
+
#
|
29
|
+
# @return [Hash, nil] a user information hash if the response is valid; +nil+ otherwise.
|
30
|
+
#
|
31
|
+
# @raise any connection errors encountered.
|
32
|
+
def user_info
|
33
|
+
parse_user_info( find_authentication_success( get_service_response_body ) )
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# turns an `<cas:authenticationSuccess>` node into a Hash;
|
39
|
+
# returns nil if given nil
|
40
|
+
def parse_user_info(node)
|
41
|
+
return nil if node.nil?
|
42
|
+
|
43
|
+
{}.tap do |hash|
|
44
|
+
node.children.each do |e|
|
45
|
+
unless e.kind_of?(Nokogiri::XML::Text) ||
|
46
|
+
e.name == 'cas:proxies' ||
|
47
|
+
e.name == 'proxies'
|
48
|
+
# There are no child elements
|
49
|
+
if e.element_children.count == 0
|
50
|
+
hash[e.name.sub(/^cas:/, '')] = e.content
|
51
|
+
elsif e.element_children.count
|
52
|
+
hash[e.name.sub(/^cas:/, '')] = [] if hash[e.name.sub(/^cas:/, '')].nil?
|
53
|
+
hash[e.name.sub(/^cas:/, '')].push parse_user_info e
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# finds an `<cas:authenticationSuccess>` node in
|
61
|
+
# a `<cas:serviceResponse>` body if present; returns nil
|
62
|
+
# if the passed body is nil or if there is no such node.
|
63
|
+
def find_authentication_success(body)
|
64
|
+
return nil if body.nil? || body == ''
|
65
|
+
begin
|
66
|
+
doc = Nokogiri::XML(body)
|
67
|
+
begin
|
68
|
+
doc.xpath('/cas:serviceResponse/cas:authenticationSuccess')
|
69
|
+
rescue Nokogiri::XML::XPath::SyntaxError
|
70
|
+
doc.xpath('/serviceResponse/authenticationSuccess')
|
71
|
+
end
|
72
|
+
rescue Nokogiri::XML::XPath::SyntaxError
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# retrieves the `<cas:serviceResponse>` XML from the CAS server
|
78
|
+
def get_service_response_body
|
79
|
+
result = ''
|
80
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
81
|
+
http.use_ssl = @uri.port == 443 || @uri.instance_of?(URI::HTTPS)
|
82
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl? && @options.disable_ssl_verification?
|
83
|
+
http.start do |c|
|
84
|
+
response = c.get "#{@uri.path}?#{@uri.query}", VALIDATION_REQUEST_HEADERS.dup
|
85
|
+
result = response.body
|
86
|
+
end
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/omniauth/cas/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Derek Lindahl"]
|
6
|
+
gem.email = ["dlindahl@customink.com"]
|
7
|
+
# gem.description = %q{TODO: Write a gem description}
|
8
|
+
gem.summary = %q{CAS Strategy for OmniAuth}
|
9
|
+
gem.homepage = "https://github.com/dlindahl/omniauth-cas"
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "omniauth-cas"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Omniauth::Cas::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'omniauth', '~> 1.0'
|
19
|
+
gem.add_dependency 'nokogiri', '~> 1.5'
|
20
|
+
gem.add_dependency 'addressable', '~> 2.2'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rake', '~> 0.9'
|
23
|
+
gem.add_development_dependency 'webmock', '~> 1.7'
|
24
|
+
gem.add_development_dependency 'simplecov', '~> 0.5.4'
|
25
|
+
gem.add_development_dependency 'rspec', '~> 2.7'
|
26
|
+
gem.add_development_dependency 'rack-test', '~> 0.6'
|
27
|
+
|
28
|
+
gem.add_development_dependency 'awesome_print'
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
|
2
|
+
<cas:authenticationSuccess>
|
3
|
+
<cas:user>psegel</cas:user>
|
4
|
+
<cas:employeeid>54</cas:employeeid>
|
5
|
+
<cas:first_name>P. Segel</cas:first_name>
|
6
|
+
<cas:first_name>Peter</cas:first_name>
|
7
|
+
<cas:last_name>Segel</cas:last_name>
|
8
|
+
<cas:email>psegel@intridea.com</cas:email>
|
9
|
+
<cas:location>Washington, D.C.</cas:location>
|
10
|
+
<cas:image>/images/user.jpg</cas:image>
|
11
|
+
<cas:phone>555-555-5555</cas:phone>
|
12
|
+
<cas:hire_date>2004-07-13</cas:hire_date>
|
13
|
+
</cas:authenticationSuccess>
|
14
|
+
</cas:serviceResponse>
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require File.expand_path( 'spec/spec_helper' )
|
2
|
+
|
3
|
+
describe OmniAuth::Strategies::CAS, :type => :strategy do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
class MyCasProvider < OmniAuth::Strategies::CAS; end # TODO: Not really needed. just an alias but it requires the :name option which might confuse users...
|
7
|
+
def app
|
8
|
+
Rack::Builder.new {
|
9
|
+
use OmniAuth::Test::PhonySession
|
10
|
+
use MyCasProvider, :name => :cas, :host => 'cas.example.org', :uid_key => :employeeid
|
11
|
+
run lambda { |env| [404, {'Content-Type' => 'text/plain'}, [env.key?('omniauth.auth').to_s]] }
|
12
|
+
}.to_app
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'GET /auth/cas' do
|
16
|
+
before do
|
17
|
+
get '/auth/cas', nil, { 'HTTP_REFERER' => 'http://myapp.com/admin/foo'}
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:redirect_params) { "service=" + CGI.escape("http://example.org/auth/cas/callback?url=http://myapp.com/admin/foo") }
|
21
|
+
subject { last_response }
|
22
|
+
|
23
|
+
it { should be_redirect }
|
24
|
+
it "should redirect to the CAS server" do
|
25
|
+
subject.headers['Location'].should == "https://cas.example.org/login?" + redirect_params
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'GET /auth/cas/callback without a ticket' do
|
30
|
+
before do
|
31
|
+
get '/auth/cas/callback'
|
32
|
+
end
|
33
|
+
|
34
|
+
subject { last_response }
|
35
|
+
|
36
|
+
it { should be_redirect }
|
37
|
+
it "should have a failure message" do
|
38
|
+
subject.headers['Location'].should == "/auth/failure?message=no_ticket"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'GET /auth/cas/callback with an invalid ticket' do
|
43
|
+
before do
|
44
|
+
stub_request(:get, /^https:\/\/cas.example.org(:443)?\/serviceValidate\?([^&]+&)?ticket=9391d/).
|
45
|
+
to_return( :body => File.read('spec/fixtures/cas_failure.xml') )
|
46
|
+
get '/auth/cas/callback?ticket=9391d'
|
47
|
+
end
|
48
|
+
|
49
|
+
subject { last_response }
|
50
|
+
|
51
|
+
it { should be_redirect }
|
52
|
+
it 'should have a failure message' do
|
53
|
+
subject.headers['Location'].should == "/auth/failure?message=invalid_ticket"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'GET /auth/cas/callback with a valid ticket' do
|
58
|
+
before do
|
59
|
+
stub_request(:get, /^https:\/\/cas.example.org(:443)?\/serviceValidate\?([^&]+&)?ticket=593af/).
|
60
|
+
with { |request| @request_uri = request.uri.to_s }.
|
61
|
+
to_return( :body => File.read('spec/fixtures/cas_success.xml') )
|
62
|
+
get '/auth/cas/callback?ticket=593af'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should strip the ticket parameter from the callback URL' do
|
66
|
+
@request_uri.scan('ticket=').length.should == 1
|
67
|
+
end
|
68
|
+
|
69
|
+
context "request.env['omniauth.auth']" do
|
70
|
+
subject { last_request.env['omniauth.auth'] }
|
71
|
+
it { should be_kind_of Hash }
|
72
|
+
its(:provider) { should == :cas }
|
73
|
+
its(:uid) { should == '54'}
|
74
|
+
|
75
|
+
context "the info hash" do
|
76
|
+
subject { last_request.env['omniauth.auth']['info'] }
|
77
|
+
it { should have(6).items }
|
78
|
+
its('name') { should == 'Peter Segel' }
|
79
|
+
its('first_name') { should == 'Peter' }
|
80
|
+
its('last_name') { should == 'Segel' }
|
81
|
+
its('email') { should == 'psegel@intridea.com' }
|
82
|
+
its('location') { should == 'Washington, D.C.' }
|
83
|
+
its('image') { should == '/images/user.jpg' }
|
84
|
+
its('phone') { should == '555-555-5555' }
|
85
|
+
end
|
86
|
+
context "the extra hash" do
|
87
|
+
subject { last_request.env['omniauth.auth']['extra'] }
|
88
|
+
it { should have(3).items }
|
89
|
+
its('user') { should == 'psegel' }
|
90
|
+
its('employeeid') { should == '54' }
|
91
|
+
its('hire_date') { should == '2004-07-13' }
|
92
|
+
end
|
93
|
+
context "the credentials hash" do
|
94
|
+
subject { last_request.env['omniauth.auth']['credentials'] }
|
95
|
+
it { should have(1).items }
|
96
|
+
its('ticket') { should == '593af' }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should call through to the master app' do
|
101
|
+
last_response.body.should == 'true'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# unless RUBY_VERSION =~ /^1\.8\.\d$/
|
106
|
+
# describe 'GET /auth/cas/callback with a valid ticket and gzipped response from the server on ruby >1.8' do
|
107
|
+
# before do
|
108
|
+
# zipped = StringIO.new
|
109
|
+
# Zlib::GzipWriter.wrap zipped do |io|
|
110
|
+
# io.write File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'cas_success.xml'))
|
111
|
+
# end
|
112
|
+
# stub_request(:get, /^https:\/\/cas.example.org(:443)?\/serviceValidate\?([^&]+&)?ticket=593af/).
|
113
|
+
# with { |request| @request_uri = request.uri.to_s }.
|
114
|
+
# to_return(:body => zipped.string, :headers => { 'content-encoding' => 'gzip' })
|
115
|
+
# get '/auth/cas/callback?ticket=593af'
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# it 'should call through to the master app when response is gzipped' do
|
119
|
+
# last_response.body.should == 'true'
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omniauth-cas
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Derek Lindahl
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-19 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: omniauth
|
16
|
+
requirement: &2165386700 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2165386700
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nokogiri
|
27
|
+
requirement: &2165386060 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.5'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2165386060
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: addressable
|
38
|
+
requirement: &2165385480 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '2.2'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2165385480
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: &2165381940 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.9'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2165381940
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: webmock
|
60
|
+
requirement: &2165381300 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '1.7'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2165381300
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: &2165380620 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.5.4
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2165380620
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rspec
|
82
|
+
requirement: &2165379960 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '2.7'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *2165379960
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rack-test
|
93
|
+
requirement: &2165379500 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0.6'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *2165379500
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: awesome_print
|
104
|
+
requirement: &2165379120 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *2165379120
|
113
|
+
description:
|
114
|
+
email:
|
115
|
+
- dlindahl@customink.com
|
116
|
+
executables: []
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- .gitignore
|
121
|
+
- .rvmrc
|
122
|
+
- .travis.yml
|
123
|
+
- Gemfile
|
124
|
+
- LICENSE
|
125
|
+
- README.md
|
126
|
+
- Rakefile
|
127
|
+
- lib/omniauth-cas.rb
|
128
|
+
- lib/omniauth/cas.rb
|
129
|
+
- lib/omniauth/cas/version.rb
|
130
|
+
- lib/omniauth/strategies/cas.rb
|
131
|
+
- lib/omniauth/strategies/cas/configuration.rb
|
132
|
+
- lib/omniauth/strategies/cas/service_ticket_validator.rb
|
133
|
+
- omniauth-cas.gemspec
|
134
|
+
- spec/fixtures/cas_failure.xml
|
135
|
+
- spec/fixtures/cas_success.xml
|
136
|
+
- spec/omniauth/strategies/cas_spec.rb
|
137
|
+
- spec/spec_helper.rb
|
138
|
+
homepage: https://github.com/dlindahl/omniauth-cas
|
139
|
+
licenses: []
|
140
|
+
post_install_message:
|
141
|
+
rdoc_options: []
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
152
|
+
requirements:
|
153
|
+
- - ! '>='
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
requirements: []
|
157
|
+
rubyforge_project:
|
158
|
+
rubygems_version: 1.8.10
|
159
|
+
signing_key:
|
160
|
+
specification_version: 3
|
161
|
+
summary: CAS Strategy for OmniAuth
|
162
|
+
test_files:
|
163
|
+
- spec/fixtures/cas_failure.xml
|
164
|
+
- spec/fixtures/cas_success.xml
|
165
|
+
- spec/omniauth/strategies/cas_spec.rb
|
166
|
+
- spec/spec_helper.rb
|