omniauth-cas3-1.1.3/ 0000755 0001756 0001757 00000000000 12645767255 013253 5 ustar pravi pravi omniauth-cas3-1.1.3/spec/ 0000755 0001756 0001757 00000000000 12645767255 014205 5 ustar pravi pravi omniauth-cas3-1.1.3/spec/fixtures/ 0000755 0001756 0001757 00000000000 12645767255 016056 5 ustar pravi pravi omniauth-cas3-1.1.3/spec/fixtures/cas_failure.xml 0000644 0001756 0001757 00000000221 12645767255 021050 0 ustar pravi pravi
omniauth-cas3-1.1.3/spec/fixtures/cas_success.xml 0000644 0001756 0001757 00000001076 12645767255 021102 0 ustar pravi pravi
psegel
54
P. Segel
Peter
Segel
psegel@intridea.com
Washington, D.C.
/images/user.jpg
555-555-5555
2004-07-13
omniauth-cas3-1.1.3/spec/fixtures/cas_success_jasig.xml 0000644 0001756 0001757 00000001173 12645767255 022255 0 ustar pravi pravi
psegel
54
P. Segel
Peter
Segel
psegel@intridea.com
Washington, D.C.
/images/user.jpg
555-555-5555
2004-07-13
omniauth-cas3-1.1.3/spec/spec_helper.rb 0000644 0001756 0001757 00000000414 12645767255 017022 0 ustar pravi pravi require 'bundler/setup'
require 'awesome_print'
RSpec.configure do |c|
c.filter_run focus: true
c.run_all_when_everything_filtered = true
end
require 'rack/test'
require 'webmock/rspec'
require 'omniauth-cas3'
OmniAuth.config.logger = Logger.new( '/dev/null' )
omniauth-cas3-1.1.3/spec/omniauth/ 0000755 0001756 0001757 00000000000 12645767255 016031 5 ustar pravi pravi omniauth-cas3-1.1.3/spec/omniauth/strategies/ 0000755 0001756 0001757 00000000000 12645767255 020203 5 ustar pravi pravi omniauth-cas3-1.1.3/spec/omniauth/strategies/cas3_spec.rb 0000644 0001756 0001757 00000017440 12645767255 022401 0 ustar pravi pravi require 'spec_helper'
describe OmniAuth::Strategies::CAS3, type: :strategy do
include Rack::Test::Methods
let(:my_cas_provider) { Class.new(OmniAuth::Strategies::CAS3) }
before do
stub_const 'MyCasProvider', my_cas_provider
end
let(:app) do
Rack::Builder.new {
use OmniAuth::Test::PhonySession
use MyCasProvider, name: :cas3, host: 'cas.example.org', ssl: false, port: 8080, uid_field: :employeeid
run lambda { |env| [404, {'Content-Type' => 'text/plain'}, [env.key?('omniauth.auth').to_s]] }
}.to_app
end
# TODO: Verify that these are even useful tests
shared_examples_for 'a CAS redirect response' do
let(:redirect_params) { 'service=' + Rack::Utils.escape("http://example.org/auth/cas3/callback?url=#{Rack::Utils.escape(return_url)}") }
before { get url, nil, request_env }
subject { last_response }
it { should be_redirect }
it 'redirects to the CAS server' do
expect(subject.headers).to include 'Location' => "http://cas.example.org:8080/login?#{redirect_params}"
end
end
describe '#cas_url' do
let(:params) { Hash.new }
let(:provider) { MyCasProvider.new(nil, params) }
subject { provider.cas_url }
it 'raises an ArgumentError' do
expect{subject}.to raise_error ArgumentError, %r{:host and :login_url MUST be provided}
end
context 'with an explicit :url option' do
let(:url) { 'https://example.org:8080/my_cas' }
let(:params) { super().merge url:url }
before { subject }
it { should eq url }
it 'parses the URL into it the appropriate strategy options' do
expect(provider.options).to include ssl:true
expect(provider.options).to include host:'example.org'
expect(provider.options).to include port:8080
expect(provider.options).to include path:'/my_cas'
end
end
context 'with explicit URL component' do
let(:params) { super().merge host:'example.org', port:1234, ssl:true, path:'/a/path' }
before { subject }
it { should eq 'https://example.org:1234/a/path' }
it 'parses the URL into it the appropriate strategy options' do
expect(provider.options).to include ssl:true
expect(provider.options).to include host:'example.org'
expect(provider.options).to include port:1234
expect(provider.options).to include path:'/a/path'
end
end
end
describe 'defaults' do
subject { MyCasProvider.default_options.to_hash }
it { should include('ssl' => true) }
end
describe 'GET /auth/cas3' do
let(:return_url) { 'http://myapp.com/admin/foo' }
context 'with a referer' do
let(:url) { '/auth/cas3' }
let(:request_env) { { 'HTTP_REFERER' => return_url } }
it_behaves_like 'a CAS redirect response'
end
context 'with an explicit return URL' do
let(:url) { "/auth/cas3?url=#{return_url}" }
let(:request_env) { {} }
it_behaves_like 'a CAS redirect response'
end
end
describe 'GET /auth/cas3/callback' do
context 'without a ticket' do
before { get '/auth/cas3/callback' }
subject { last_response }
it { should be_redirect }
it 'redirects with a failure message' do
expect(subject.headers).to include 'Location' => '/auth/failure?message=no_ticket&strategy=cas3'
end
end
context 'with an invalid ticket' do
before do
stub_request(:get, /^http:\/\/cas.example.org:8080?\/p3\/serviceValidate\?([^&]+&)?ticket=9391d/).
to_return( body: File.read('spec/fixtures/cas_failure.xml') )
get '/auth/cas3/callback?ticket=9391d'
end
subject { last_response }
it { should be_redirect }
it 'redirects with a failure message' do
expect(subject.headers).to include 'Location' => '/auth/failure?message=invalid_ticket&strategy=cas3'
end
end
describe 'with a valid ticket' do
shared_examples :successful_validation do
before do
stub_request(:get, /^http:\/\/cas.example.org:8080?\/p3\/serviceValidate\?([^&]+&)?ticket=593af/)
.with { |request| @request_uri = request.uri.to_s }
.to_return( body: File.read("spec/fixtures/#{xml_file_name}") )
get "/auth/cas3/callback?ticket=593af&url=#{return_url}"
end
it 'strips the ticket parameter from the callback URL' do
expect(@request_uri.scan('ticket=').size).to eq 1
end
it 'properly encodes the service URL' do
expect(WebMock).to have_requested(:get, 'http://cas.example.org:8080/p3/serviceValidate')
.with(query: {
ticket: '593af',
service: 'http://example.org/auth/cas3/callback?url=' + Rack::Utils.escape('http://127.0.0.10/?some=parameter')
})
end
context "request.env['omniauth.auth']" do
subject { last_request.env['omniauth.auth'] }
it { should be_kind_of Hash }
it 'identifes the provider' do
expect(subject.provider).to eq :cas3
end
it 'returns the UID of the user' do
expect(subject.uid).to eq '54'
end
context 'the info hash' do
subject { last_request.env['omniauth.auth']['info'] }
it 'includes user info attributes' do
expect(subject.name).to eq 'Peter Segel'
expect(subject.first_name).to eq 'Peter'
expect(subject.last_name).to eq 'Segel'
expect(subject.nickname).to eq 'psegel'
expect(subject.email).to eq 'psegel@intridea.com'
expect(subject.location).to eq 'Washington, D.C.'
expect(subject.image).to eq '/images/user.jpg'
expect(subject.phone).to eq '555-555-5555'
end
end
context 'the extra hash' do
subject { last_request.env['omniauth.auth']['extra'] }
it 'includes additional user attributes' do
expect(subject.user).to eq 'psegel'
expect(subject.employeeid).to eq '54'
expect(subject.hire_date).to eq '2004-07-13'
end
end
context 'the credentials hash' do
subject { last_request.env['omniauth.auth']['credentials'] }
it 'has a ticket value' do
expect(subject.ticket).to eq '593af'
end
end
end
it 'calls through to the master app' do
expect(last_response.body).to eq 'true'
end
end
let(:return_url) { 'http://127.0.0.10/?some=parameter' }
context 'with JASIG flavored XML' do
let(:xml_file_name) { 'cas_success_jasig.xml' }
it_behaves_like :successful_validation
end
context 'with classic XML' do
let(:xml_file_name) { 'cas_success.xml' }
it_behaves_like :successful_validation
end
end
end
describe 'POST /auth/cas3/callback' do
describe 'with a Single Sign-Out logoutRequest' do
let(:logoutRequest) do
%Q[
@NOT_USED@
ST-123456-123abc456def
]
end
let(:logout_request) { double('logout_request', call:[200,{},'OK']) }
subject do
post 'auth/cas3/callback', logoutRequest:logoutRequest
end
before do
allow_any_instance_of(MyCasProvider)
.to receive(:logout_request_service)
.and_return double('LogoutRequest', new:logout_request)
subject
end
it 'initializes a LogoutRequest' do
expect(logout_request).to have_received :call
end
end
end
end
omniauth-cas3-1.1.3/spec/omniauth/strategies/cas3/ 0000755 0001756 0001757 00000000000 12645767255 021034 5 ustar pravi pravi omniauth-cas3-1.1.3/spec/omniauth/strategies/cas3/logout_request_spec.rb 0000644 0001756 0001757 00000007673 12645767255 025471 0 ustar pravi pravi require 'spec_helper'
describe OmniAuth::Strategies::CAS3::LogoutRequest do
let(:strategy) { double('strategy') }
let(:env) do
{ 'rack.input' => StringIO.new('','r') }
end
let(:request) { double('request', params:params, env:env) }
let(:params) { { 'url' => url, 'logoutRequest' => logoutRequest } }
let(:url) { 'http://notes.dev/signed_in' }
let(:logoutRequest) do
%Q[
@NOT_USED@
ST-123456-123abc456def
]
end
subject { described_class.new(strategy, request).call(options) }
describe 'SAML attributes' do
let(:callback) { Proc.new{} }
let(:options) do
{ on_single_sign_out: callback }
end
before do
@rack_input = nil
allow(callback).to receive(:call) do |req|
@rack_input = req.env['rack.input'].read
true
end
end
it 'are parsed and injected into the Rack Request parameters', :skip => true do
subject
expect(@rack_input).to eq 'name_id=%40NOT_USED%40&session_index=ST-123456-123abc456def'
end
it 'are parsed and injected even if saml defined inside NameID', :skip => true do
request.params['logoutRequest'] =
%Q[
@NOT_USED@
ST-foo-bar
]
subject
expect(@rack_input).to eq 'name_id=%40NOT_USED%40&session_index=ST-foo-bar'
end
it 'are parsed and injected even if saml and samlp namespaces not defined', :skip => true do
request.params['logoutRequest'] =
%Q[
@NOT_USED@
ST-789000-456def789ghi
]
subject
expect(@rack_input).to eq 'name_id=%40NOT_USED%40&session_index=ST-789000-456def789ghi'
end
context 'that raise when parsed' do
let(:env) { { 'rack.input' => nil } }
before do
allow(strategy).to receive(:fail!)
subject
expect(strategy).to have_received(:fail!)
end
it 'responds with an error', skip: true do
expect(strategy).to have_received(:fail!)
end
end
end
describe 'with a configured callback' do
let(:options) do
{ on_single_sign_out: callback }
end
context 'that returns TRUE' do
let(:callback) { Proc.new{true} }
it 'responds with OK', skip: true do
expect(subject[0]).to eq 200
expect(subject[2].body).to eq ['OK']
end
end
context 'that returns Nil' do
let(:callback) { Proc.new{} }
it 'responds with OK', skip: true do
expect(subject[0]).to eq 200
expect(subject[2].body).to eq ['OK']
end
end
context 'that returns a tuple' do
let(:callback) { Proc.new{ [400,{},'Bad Request'] } }
it 'responds with OK', skip: true do
expect(subject[0]).to eq 400
expect(subject[2].body).to eq ['Bad Request']
end
end
context 'that raises an error' do
let(:exception) { RuntimeError.new('error' )}
let(:callback) { Proc.new{raise exception} }
before do
allow(strategy).to receive(:fail!)
subject
end
it 'responds with an error', skip: true do
expect(strategy).to have_received(:fail!)
.with(:logout_request, exception)
end
end
end
end
omniauth-cas3-1.1.3/spec/omniauth/strategies/cas3/service_ticket_validator_spec.rb 0000644 0001756 0001757 00000002562 12645767255 027450 0 ustar pravi pravi require 'spec_helper'
describe OmniAuth::Strategies::CAS3::ServiceTicketValidator do
let(:strategy) do
double('strategy',
service_validate_url: 'https://example.org/serviceValidate'
)
end
let(:provider_options) do
double('provider_options',
disable_ssl_verification?: false,
ca_path: '/etc/ssl/certsZOMG'
)
end
let(:validator) do
OmniAuth::Strategies::CAS3::ServiceTicketValidator.new( strategy, provider_options, '/foo', nil )
end
describe '#call' do
before do
stub_request(:get, 'https://example.org/serviceValidate?')
.to_return(status: 200, body: '')
end
subject { validator.call }
it 'returns itself' do
expect(subject).to eq validator
end
it 'uses the configured CA path' do
subject
expect(provider_options).to have_received :ca_path
end
end
describe '#user_info' do
let(:ok_fixture) do
File.expand_path(File.join(File.dirname(__FILE__), '../../../fixtures/cas_success.xml'))
end
let(:service_response) { File.read(ok_fixture) }
before do
stub_request(:get, 'https://example.org/serviceValidate?')
.to_return(status: 200, body:service_response)
validator.call
end
subject { validator.user_info }
it 'parses user info from the response' do
expect(subject).to include 'user' => 'psegel'
end
end
end
omniauth-cas3-1.1.3/LICENSE 0000644 0001756 0001757 00000002132 12645767255 014256 0 ustar pravi pravi Copyright (c) 2011 Derek Lindahl and CustomInk, LLC
Copyright (c) 2015 tduehr
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. omniauth-cas3-1.1.3/.editorconfig 0000644 0001756 0001757 00000000563 12645767255 015734 0 ustar pravi pravi # EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# Change these settings to your own preference
indent_style = space
indent_size = 2
# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true omniauth-cas3-1.1.3/.travis.yml 0000644 0001756 0001757 00000000201 12645767255 015355 0 ustar pravi pravi rvm:
- 1.9.3
- 2.0.0
- 2.1
- 2.2
branches:
only:
- master
- /.*-test$/
before_install:
- gem install bundler
omniauth-cas3-1.1.3/omniauth-cas3.gemspec 0000644 0001756 0001757 00000002206 12645767255 017273 0 ustar pravi pravi # -*- encoding: utf-8 -*-
require File.expand_path('../lib/omniauth/cas3/version', __FILE__)
Gem::Specification.new do |gem|
gem.authors = ["Derek Lindahl, tduehr"]
gem.email = ["td@matasano.com"]
gem.summary = %q{CAS 3.0 Strategy for OmniAuth}
gem.description = gem.summary
gem.homepage = "https://github.com/tduehr/omniauth-cas3"
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
gem.files = `git ls-files`.split("\n")
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
gem.name = "omniauth-cas3"
gem.require_paths = ["lib"]
gem.version = Omniauth::Cas3::VERSION
gem.add_dependency 'omniauth', '~> 1.2'
gem.add_dependency 'nokogiri', '~> 1.6.6'
gem.add_dependency 'addressable', '~> 2.3'
gem.add_development_dependency 'rake', '~> 10.0'
gem.add_development_dependency 'webmock', '~> 1.19.0'
gem.add_development_dependency 'rspec', '~> 3.1.0'
gem.add_development_dependency 'rack-test', '~> 0.6'
gem.add_development_dependency 'awesome_print'
end
omniauth-cas3-1.1.3/README.md 0000644 0001756 0001757 00000012134 12645767255 014533 0 ustar pravi pravi # OmniAuth CAS Strategy [![Gem Version][version_badge]][version] [![Build Status][travis_status]][travis]
[version_badge]: https://badge.fury.io/rb/omniauth-cas3.png
[version]: http://badge.fury.io/rb/omniauth-cas3
[travis]: http://travis-ci.org/tduehr/omniauth-cas3
[travis_status]: https://secure.travis-ci.org/dlindahl/omniauth-cas3.png
[releases]: https://github.com/tduehr/omniauth-cas3/releases
This is a OmniAuth 1.0 compatible port of the previously available
[OmniAuth CAS strategy][old_omniauth_cas] that was bundled with OmniAuth 0.3. This strategy haas also been updated for CAS protocol version 3.0 and patched to deal with namespace issues.
* [View the documentation][document_up]
* [Changelog][releases]
## Installation
Add this line to your application's Gemfile:
gem 'omniauth-cas3'
And then execute:
$ bundle
Or install it yourself as:
$ gem install omniauth-cas3
## Usage
Use like any other OmniAuth strategy:
```ruby
Rails.application.config.middleware.use OmniAuth::Builder do
provider :cas3, host: 'cas.yourdomain.com'
end
```
### Configuration Options
#### Required
OmniAuth CAS requires at least one of the following two configuration options:
* `url` - Defines the URL of your CAS server (i.e. `http://example.org:8080`)
* `host` - Defines the host of your CAS server (i.e. `example.org`).
#### Optional
Other configuration options:
* `port` - The port to use for your configured CAS `host`. Optional if using `url`.
* `ssl` - TRUE to connect to your CAS server over SSL. Optional if using `url`.
* `service_validate_url` - The URL to use to validate a user. Defaults to `'/serviceValidate'`.
* `callback_url` - The URL custom URL path which CAS uses to call back to the service. Defaults to `/users/auth/cas3/callback`.
* `logout_url` - The URL to use to logout a user. Defaults to `'/logout'`.
* `login_url` - Defines the URL used to prompt users for their login information. Defaults to `/login` If no `host` is configured, the host application's domain will be used.
* `uid_field` - The user data attribute to use as your user's unique identifier. Defaults to `'user'` (which usually contains the user's login name).
* `ca_path` - Optional when `ssl` is `true`. Sets path of a CA certification directory. See [Net::HTTP][net_http] for more details.
* `disable_ssl_verification` - Optional when `ssl` is true. Disables verification.
* `on_single_sign_out` - Optional. Callback used when a [CAS 3.1 Single Sign Out][sso]
request is received.
* `fetch_raw_info` - Optional. Callback used to return additional "raw" user
info from other sources.
```ruby
provider :cas3,
fetch_raw_info: lambda { |strategy, options, ticket, user_info|
ExternalService.get(user_info[:user]).attributes
}
```
Configurable options for values returned by CAS:
* `uid_key` - The user ID data attribute to use as your user's unique identifier. Defaults to `'user'` (which usually contains the user's login name).
* `name_key` - The data attribute containing user first and last name. Defaults to `'name'`.
* `email_key` - The data attribute containing user email address. Defaults to `'email'`.
* `nickname_key` - The data attribute containing user's nickname. Defaults to `'user'`.
* `first_name_key` - The data attribute containing user first name. Defaults to `'first_name'`.
* `last_name_key` - The data attribute containing user last name. Defaults to `'last_name'`.
* `location_key` - The data attribute containing user location/address. Defaults to `'location'`.
* `image_key` - The data attribute containing user image/picture. Defaults to `'image'`.
* `phone_key` - The data attribute containing user contact phone number. Defaults to `'phone'`.
## Migrating from OmniAuth 0.3
Given the following OmniAuth 0.3 configuration:
```ruby
provider :CAS, cas_server: 'https://cas.example.com/cas/'
```
Your new settings should look similar to this:
```ruby
provider :cas3,
host: 'cas.example.com',
login_url: '/cas/login',
service_validate_url: '/cas/p3/serviceValidate'
```
If you encounter problems wih SSL certificates you may want to set the `ca_path` parameter or activate `disable_ssl_verification` (not recommended).
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## Thanks
Special thanks go out to the following people
* @dlindahl For the original work in porting this from OmniAuth 0.3
* Phillip Aldridge (@iterateNZ) and JB Barth (@jbbarth) for helping out with Issue #3
* Elber Ribeiro (@dynaum) for Ubuntu SSL configuration support
* @rbq for README updates and OmniAuth 0.3 migration guide
[old_omniauth_cas]: https://github.com/intridea/omniauth/blob/0-3-stable/oa-enterprise/lib/omniauth/strategies/cas.rb
[document_up]: http://tduehr.github.com/omniauth-cas3/
[net_http]: http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html
[sso]: https://wiki.jasig.org/display/CASUM/Single+Sign+Out
omniauth-cas3-1.1.3/Gemfile 0000644 0001756 0001757 00000000142 12645767255 014543 0 ustar pravi pravi source 'https://rubygems.org'
# Specify your gem's dependencies in omniauth-cas3.gemspec
gemspec
omniauth-cas3-1.1.3/metadata.yml 0000644 0001756 0001757 00000011211 12645767255 015552 0 ustar pravi pravi --- !ruby/object:Gem::Specification
name: omniauth-cas3
version: !ruby/object:Gem::Version
version: 1.1.3
platform: ruby
authors:
- Derek Lindahl, tduehr
autorequire:
bindir: bin
cert_chain: []
date: 2015-10-28 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: omniauth
requirement: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '1.2'
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '1.2'
- !ruby/object:Gem::Dependency
name: nokogiri
requirement: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: 1.6.6
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: 1.6.6
- !ruby/object:Gem::Dependency
name: addressable
requirement: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '2.3'
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '2.3'
- !ruby/object:Gem::Dependency
name: rake
requirement: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '10.0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '10.0'
- !ruby/object:Gem::Dependency
name: webmock
requirement: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: 1.19.0
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: 1.19.0
- !ruby/object:Gem::Dependency
name: rspec
requirement: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: 3.1.0
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: 3.1.0
- !ruby/object:Gem::Dependency
name: rack-test
requirement: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '0.6'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - "~>"
- !ruby/object:Gem::Version
version: '0.6'
- !ruby/object:Gem::Dependency
name: awesome_print
requirement: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: '0'
type: :development
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: '0'
description: CAS 3.0 Strategy for OmniAuth
email:
- td@matasano.com
executables: []
extensions: []
extra_rdoc_files: []
files:
- ".editorconfig"
- ".gitignore"
- ".travis.yml"
- Gemfile
- LICENSE
- README.md
- Rakefile
- lib/omniauth-cas3.rb
- lib/omniauth/cas3.rb
- lib/omniauth/cas3/version.rb
- lib/omniauth/strategies/cas3.rb
- lib/omniauth/strategies/cas3/logout_request.rb
- lib/omniauth/strategies/cas3/service_ticket_validator.rb
- omniauth-cas3.gemspec
- spec/fixtures/cas_failure.xml
- spec/fixtures/cas_success.xml
- spec/fixtures/cas_success_jasig.xml
- spec/omniauth/strategies/cas3/logout_request_spec.rb
- spec/omniauth/strategies/cas3/service_ticket_validator_spec.rb
- spec/omniauth/strategies/cas3_spec.rb
- spec/spec_helper.rb
homepage: https://github.com/tduehr/omniauth-cas3
licenses: []
metadata: {}
post_install_message:
rdoc_options: []
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: '0'
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: '0'
requirements: []
rubyforge_project:
rubygems_version: 2.4.8
signing_key:
specification_version: 4
summary: CAS 3.0 Strategy for OmniAuth
test_files:
- spec/fixtures/cas_failure.xml
- spec/fixtures/cas_success.xml
- spec/fixtures/cas_success_jasig.xml
- spec/omniauth/strategies/cas3/logout_request_spec.rb
- spec/omniauth/strategies/cas3/service_ticket_validator_spec.rb
- spec/omniauth/strategies/cas3_spec.rb
- spec/spec_helper.rb
has_rdoc:
omniauth-cas3-1.1.3/lib/ 0000755 0001756 0001757 00000000000 12645767255 014021 5 ustar pravi pravi omniauth-cas3-1.1.3/lib/omniauth/ 0000755 0001756 0001757 00000000000 12645767255 015645 5 ustar pravi pravi omniauth-cas3-1.1.3/lib/omniauth/strategies/ 0000755 0001756 0001757 00000000000 12645767255 020017 5 ustar pravi pravi omniauth-cas3-1.1.3/lib/omniauth/strategies/cas3.rb 0000644 0001756 0001757 00000016300 12645767255 021175 0 ustar pravi pravi require 'omniauth'
require 'addressable/uri'
module OmniAuth
module Strategies
class CAS3
include OmniAuth::Strategy
# Custom Exceptions
class MissingCASTicket < StandardError; end
class InvalidCASTicket < StandardError; end
autoload :ServiceTicketValidator, 'omniauth/strategies/cas3/service_ticket_validator'
autoload :LogoutRequest, 'omniauth/strategies/cas3/logout_request'
attr_accessor :raw_info
alias_method :user_info, :raw_info
option :name, :cas3 # Required property by OmniAuth::Strategy
option :host, nil
option :port, nil
option :path, nil
option :ssl, true
option :service_validate_url, '/p3/serviceValidate'
option :login_url, '/login'
option :logout_url, '/logout'
option :on_single_sign_out, Proc.new {}
# A Proc or lambda that returns a Hash of additional user info to be
# merged with the info returned by the CAS server.
#
# @param [Object] An instance of OmniAuth::Strategies::CAS for the current request
# @param [String] The user's Service Ticket value
# @param [Hash] The user info for the Service Ticket returned by the CAS server
#
# @return [Hash] Extra user info
option :fetch_raw_info, Proc.new { Hash.new }
# Make all the keys configurable with some defaults set here
option :uid_field, 'user'
option :name_key, 'name'
option :email_key, 'email'
option :nickname_key, 'user'
option :first_name_key, 'first_name'
option :last_name_key, 'last_name'
option :location_key, 'location'
option :image_key, 'image'
option :phone_key, 'phone'
# As required by https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
AuthHashSchemaKeys = %w{name email nickname first_name last_name location image phone}
info do
prune!({
name: raw_info[options[:name_key].to_s],
email: raw_info[options[:email_key].to_s],
nickname: raw_info[options[:nickname_key].to_s],
first_name: raw_info[options[:first_name_key].to_s],
last_name: raw_info[options[:last_name_key].to_s],
location: raw_info[options[:location_key].to_s],
image: raw_info[options[:image_key].to_s],
phone: raw_info[options[:phone_key].to_s]
})
end
extra do
prune!(
raw_info.delete_if{ |k,v| AuthHashSchemaKeys.include?(k) }
)
end
uid do
raw_info[options[:uid_field].to_s]
end
credentials do
prune!({ ticket: @ticket })
end
def callback_phase
if on_sso_path?
single_sign_out_phase
else
@ticket = request.params['ticket']
return fail!(:no_ticket, MissingCASTicket.new('No CAS Ticket')) unless @ticket
fetch_raw_info(@ticket)
return fail!(:invalid_ticket, InvalidCASTicket.new('Invalid CAS Ticket')) if raw_info.empty?
super
end
end
def request_phase
service_url = append_params(callback_url, return_url)
[
302,
{
'Location' => login_url(service_url),
'Content-Type' => 'text/plain'
},
["You are being redirected to CAS for sign-in."]
]
end
def on_sso_path?
request.post? && request.params.has_key?('logoutRequest')
end
def single_sign_out_phase
logout_request_service.new(self, request).call(options)
end
# Build a CAS host with protocol and port
#
#
def cas_url
extract_url if options['url']
validate_cas_setup
@cas_url ||= begin
uri = Addressable::URI.new
uri.host = options.host
uri.scheme = options.ssl ? 'https' : 'http'
uri.port = options.port
uri.path = options.path
uri.to_s
end
end
def extract_url
url = Addressable::URI.parse(options.delete('url'))
options.merge!(
'host' => url.host,
'port' => url.port,
'path' => url.path,
'ssl' => url.scheme == 'https'
)
end
def validate_cas_setup
if options.host.nil? || options.login_url.nil?
raise ArgumentError.new(":host and :login_url MUST be provided")
end
end
# Build a service-validation URL from +service+ and +ticket+.
# If +service+ has a ticket param, first remove it. URL-encode
# +service+ and add it and the +ticket+ as paraemters to the
# CAS serviceValidate URL.
#
# @param [String] service the service (a.k.a. return-to) URL
# @param [String] ticket the ticket to validate
#
# @return [String] a URL like `http://cas.mycompany.com/serviceValidate?service=...&ticket=...`
def service_validate_url(service_url, ticket)
service_url = Addressable::URI.parse(service_url)
service_url.query_values = service_url.query_values.tap { |qs| qs.delete('ticket') }
cas_url + append_params(options.service_validate_url, {
service: service_url.to_s,
ticket: ticket
})
end
# Build a CAS login URL from +service+.
#
# @param [String] service the service (a.k.a. return-to) URL
#
# @return [String] a URL like `http://cas.mycompany.com/login?service=...`
def login_url(service)
cas_url + append_params(options.login_url, { service: service })
end
# Adds URL-escaped +parameters+ to +base+.
#
# @param [String] base the base URL
# @param [String] params the parameters to append to the URL
#
# @return [String] the new joined URL.
def append_params(base, params)
params = params.each { |k,v| v = Rack::Utils.escape(v) }
Addressable::URI.parse(base).tap do |base_uri|
base_uri.query_values = (base_uri.query_values || {}).merge(params)
end.to_s
end
# Validate the Service Ticket
# @return [Object] the validated Service Ticket
def validate_service_ticket(ticket)
ServiceTicketValidator.new(self, options, callback_url, ticket).call
end
private
def fetch_raw_info(ticket)
ticket_user_info = validate_service_ticket(ticket).user_info
custom_user_info = options.fetch_raw_info.call(self, options, ticket, ticket_user_info)
self.raw_info = ticket_user_info.merge(custom_user_info)
end
# Deletes Hash pairs with `nil` values.
# From https://github.com/mkdynamic/omniauth-facebook/blob/972ed5e3456bcaed7df1f55efd7c05c216c8f48e/lib/omniauth/strategies/facebook.rb#L122-127
def prune!(hash)
hash.delete_if do |_, value|
prune!(value) if value.is_a?(Hash)
value.nil? || (value.respond_to?(:empty?) && value.empty?)
end
end
def return_url
# If the request already has a `url` parameter, then it will already be appended to the callback URL.
if request.params && request.params['url']
{}
else
{ url: request.referer }
end
end
def logout_request_service
LogoutRequest
end
end
end
end
OmniAuth.config.add_camelization 'cas3', 'CAS3'
omniauth-cas3-1.1.3/lib/omniauth/strategies/cas3/ 0000755 0001756 0001757 00000000000 12645767255 020650 5 ustar pravi pravi omniauth-cas3-1.1.3/lib/omniauth/strategies/cas3/logout_request.rb 0000644 0001756 0001757 00000004463 12645767255 024265 0 ustar pravi pravi module OmniAuth
module Strategies
class CAS3
class LogoutRequest
def initialize(strategy, request)
@strategy, @request = strategy, request
end
def call(options = {})
@options = options
begin
result = single_sign_out_callback.call(*logout_request)
rescue StandardError => err
return @strategy.fail! :logout_request, err
else
result = [200,{},'OK'] if result == true || result.nil?
ensure
return unless result
# TODO: Why does ActionPack::Response return [status,headers,body]
# when Rack::Response#new wants [body,status,headers]? Additionally,
# why does Rack::Response differ in argument order from the usual
# Rack-like [status,headers,body] array?
return Rack::Response.new(result[2],result[0],result[1]).finish
end
end
private
def logout_request
@logout_request ||= begin
saml = parse_and_ensure_namespaces(@request.params['logoutRequest'])
ns = saml.collect_namespaces
name_id = saml.xpath('//saml:NameID', ns).text
sess_idx = saml.xpath('//samlp:SessionIndex', ns).text
inject_params(name_id:name_id, session_index:sess_idx)
@request
end
end
def parse_and_ensure_namespaces(logout_request_xml)
doc = Nokogiri.parse(logout_request_xml)
ns = doc.collect_namespaces
if ns.include?('xmlns:samlp') && ns.include?('xmlns:saml')
doc
else
add_namespaces(doc)
end
end
def add_namespaces(logout_request_doc)
root = logout_request_doc.root
root.add_namespace('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol')
root.add_namespace('saml', 'urn:oasis:names:tc:SAML:2.0:assertion\\')
# In order to add namespaces properly we need to re-parse the document
Nokogiri.parse(logout_request_doc.to_s)
end
def inject_params(new_params)
new_params.each do |key, val|
@request.update_param(key, val)
end
end
def single_sign_out_callback
@options[:on_single_sign_out]
end
end
end
end
end
omniauth-cas3-1.1.3/lib/omniauth/strategies/cas3/service_ticket_validator.rb 0000644 0001756 0001757 00000007131 12645767255 026247 0 ustar pravi pravi require 'net/http'
require 'net/https'
require 'nokogiri'
module OmniAuth
module Strategies
class CAS3
class ServiceTicketValidator
VALIDATION_REQUEST_HEADERS = { 'Accept' => '*/*' }
# Build a validator from a +configuration+, a
# +return_to+ URL, and a +ticket+.
#
# @param [Hash] options the OmniAuth Strategy options
# @param [String] return_to_url the URL of this CAS client service
# @param [String] ticket the service ticket to validate
def initialize(strategy, options, return_to_url, ticket)
@options = options
@uri = URI.parse(strategy.service_validate_url(return_to_url, ticket))
end
# Executes a network request to process the CAS Service Response
def call
@response_body = get_service_response_body
@success_body = find_authentication_success(@response_body)
self
end
# Request validation of the ticket from the CAS server's
# serviceValidate (CAS 2.0) function.
#
# Swallows all XML parsing errors (and returns +nil+ in those cases).
#
# @return [Hash, nil] a user information hash if the response is valid; +nil+ otherwise.
#
# @raise any connection errors encountered.
def user_info
parse_user_info(@success_body)
end
private
# turns an `` node into a Hash;
# returns nil if given nil
def parse_user_info(node)
return nil if node.nil?
{}.tap do |hash|
node.children.each do |e|
node_name = e.name.sub(/^cas:/, '')
unless e.kind_of?(Nokogiri::XML::Text) || node_name == 'proxies'
# There are no child elements
if e.element_children.count == 0
hash[node_name] = e.content
elsif e.element_children.count
# JASIG style extra attributes
if node_name == 'attributes'
hash.merge!(parse_user_info(e))
else
hash[node_name] = [] if hash[node_name].nil?
hash[node_name].push(parse_user_info(e))
end
end
end
end
end
end
# finds an `` node in
# a `` body if present; returns nil
# if the passed body is nil or if there is no such node.
def find_authentication_success(body)
return nil if body.nil? || body == ''
begin
doc = Nokogiri::XML(body)
begin
doc.xpath('/cas:serviceResponse/cas:authenticationSuccess')
rescue Nokogiri::XML::XPath::SyntaxError
doc.xpath('/serviceResponse/authenticationSuccess')
end
rescue Nokogiri::XML::XPath::SyntaxError
nil
end
end
# retrieves the `` XML from the CAS server
def get_service_response_body
result = ''
http = Net::HTTP.new(@uri.host, @uri.port)
http.use_ssl = @uri.port == 443 || @uri.instance_of?(URI::HTTPS)
if http.use_ssl?
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @options.disable_ssl_verification?
http.ca_path = @options.ca_path
end
http.start do |c|
response = c.get "#{@uri.path}?#{@uri.query}", VALIDATION_REQUEST_HEADERS.dup
result = response.body
end
result
end
end
end
end
end
omniauth-cas3-1.1.3/lib/omniauth/cas3.rb 0000644 0001756 0001757 00000000102 12645767255 017014 0 ustar pravi pravi require 'omniauth/cas3/version'
require 'omniauth/strategies/cas3' omniauth-cas3-1.1.3/lib/omniauth/cas3/ 0000755 0001756 0001757 00000000000 12645767255 016476 5 ustar pravi pravi omniauth-cas3-1.1.3/lib/omniauth/cas3/version.rb 0000644 0001756 0001757 00000000076 12645767255 020513 0 ustar pravi pravi module Omniauth
module Cas3
VERSION = '1.1.3'
end
end
omniauth-cas3-1.1.3/lib/omniauth-cas3.rb 0000644 0001756 0001757 00000000030 12645767255 017012 0 ustar pravi pravi require 'omniauth/cas3'
omniauth-cas3-1.1.3/Rakefile 0000644 0001756 0001757 00000000516 12645767255 014722 0 ustar pravi pravi #!/usr/bin/env rake
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
desc 'Default: run specs.'
task default: :spec
desc 'Run specs'
RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = '--require spec_helper --color --order rand'
end
task :test do
fail %q{This application uses RSpec. Try running "rake spec"}
end
omniauth-cas3-1.1.3/.gitignore 0000644 0001756 0001757 00000000264 12645767255 015245 0 ustar pravi pravi *~
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
vendor
# RSpec
.rspec