casual 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.markdown +39 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/casual.gemspec +54 -0
- data/lib/casual.rb +50 -0
- data/test/helper.rb +12 -0
- data/test/test_casual.rb +42 -0
- metadata +84 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Zach Holman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Casual
|
2
|
+
### Casual is a tiny [CAS](http://en.wikipedia.org/wiki/Central_Authentication_Service) client
|
3
|
+
|
4
|
+
There's a [few](http://github.com/gunark/rubycas-client) [CAS](http://github.com/p8/casablanca) [clients](http://github.com/jamesarosen/casrack_the_authenticator) in [the Ruby world](http://github.com/search?langOverride=&language=rb&q=cas&repo=&start_value=1&type=Repositories&x=25&y=13). Go check them out; there's a very good chance they'll fit your needs. I'll wait.
|
5
|
+
|
6
|
+
Cool. What I didn't like from existing solutions was that they assumed you were using Rails, they assumed you would use CAS in a particular fashion, and CAS seemed too straightforward to muddy it up with a ten-thousand line client library.
|
7
|
+
|
8
|
+
Casual is a übertiny client that doesn't hook into a Rails `before_filter` or deep into Rack middleware. It'll work in irb, it'll work in a simple controller, it'll work underwater. It's based off of another tiny client from [Texas A&M](http://http.tamu.edu/auth/caslibraries/ruby/), except generalized for use outside the school and to avoid REXML (ew).
|
9
|
+
|
10
|
+
Casual will work for casual use, like simple and straightforward authentication requirements or as a way to programmatically play around with and understand CAS itself.
|
11
|
+
|
12
|
+
## Codes
|
13
|
+
|
14
|
+
### Fake end-to-end CAS authentication
|
15
|
+
This bypasses the intermediary CAS single sign-on point, which is frowned upon in the CAS docs since the client gains access to usernames + passwords. But it's also a-nice-to-have if you're building an internal app that is entirely in your control.
|
16
|
+
|
17
|
+
require 'casual'
|
18
|
+
casual = Casual::Client.new(:server_path => 'local-cas-server'
|
19
|
+
:port => 443, # defaults to 443 (SSL)
|
20
|
+
:callback_url => 'http://your.example.com')
|
21
|
+
casual.authenticate('holman','super_secret_password')
|
22
|
+
# => returns 'holman' if I'm logged in, or nil if not
|
23
|
+
|
24
|
+
### Simulate traditional CAS authentication
|
25
|
+
This is closer to the normal CAS authentication process. It requires that you send the user off to your CAS login page to transfer tickets between your app and the CAS server, so you can't just do it all in one request.
|
26
|
+
|
27
|
+
require 'casual'
|
28
|
+
casual = Casual::Client.new(:server_path => 'local-cas-server'
|
29
|
+
:port => 443, # defaults to 443 (SSL)
|
30
|
+
:callback_url => 'http://your.example.com')
|
31
|
+
casual.authentication_url
|
32
|
+
# returns URL your user should be redirected to
|
33
|
+
# after CAS login, redirects you to +callback_url+ with ticket as param
|
34
|
+
casual.user_login(ticket)
|
35
|
+
# returns username if valid, nil if invalid
|
36
|
+
|
37
|
+
## Casual.
|
38
|
+
|
39
|
+
by [@holman](http://twitter.com/holman).
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "casual"
|
8
|
+
gem.summary = "A tiny CAS client for Ruby"
|
9
|
+
gem.description = "A tiny CAS client for Ruby"
|
10
|
+
gem.email = "github.com@zachholman.com"
|
11
|
+
gem.homepage = "http://github.com/holman/casual"
|
12
|
+
gem.authors = ["Zach Holman"]
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
gem.add_dependency 'nokogiri'
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "casual #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/casual.gemspec
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{casual}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Zach Holman"]
|
12
|
+
s.date = %q{2010-03-31}
|
13
|
+
s.description = %q{A tiny CAS client for Ruby}
|
14
|
+
s.email = %q{github.com@zachholman.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"casual.gemspec",
|
27
|
+
"lib/casual.rb",
|
28
|
+
"test/helper.rb",
|
29
|
+
"test/test_casual.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/holman/casual}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.6}
|
35
|
+
s.summary = %q{A tiny CAS client for Ruby}
|
36
|
+
s.test_files = [
|
37
|
+
"test/helper.rb",
|
38
|
+
"test/test_casual.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
49
|
+
end
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
data/lib/casual.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Casual
|
5
|
+
class Client
|
6
|
+
attr_accessor :server_path, :callback_url, :port
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@server_path = config[:server_path]
|
10
|
+
@callback_url = config[:callback_url]
|
11
|
+
@port = config[:port] || 443
|
12
|
+
end
|
13
|
+
|
14
|
+
def authorization_url
|
15
|
+
"#{server_url}/login?service=#{callback_url}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate(username,password)
|
19
|
+
ticket = acquire_ticket
|
20
|
+
params = "username=#{username}&password=#{password}<=#{ticket}"
|
21
|
+
status,response = connection.post('/login', params)#.last
|
22
|
+
(status.code == '200') ? username : nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def acquire_ticket
|
26
|
+
login_page = connection.get('/login')
|
27
|
+
Nokogiri::HTML(login_page.body).css('input#lt').first['value']
|
28
|
+
end
|
29
|
+
|
30
|
+
def connection
|
31
|
+
http = Net::HTTP.new(server_path, port)
|
32
|
+
http.use_ssl = true
|
33
|
+
http
|
34
|
+
end
|
35
|
+
|
36
|
+
def authenticate_ticket(ticket)
|
37
|
+
connection.get("/serviceValidate?service=#{callback_url}&ticket=#{ticket}").body
|
38
|
+
end
|
39
|
+
|
40
|
+
def user_login(ticket)
|
41
|
+
user = Nokogiri::XML(authenticate_ticket(ticket)).xpath('//cas:authenticationSuccess //cas:user').text
|
42
|
+
user.strip != '' ? user : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def server_url
|
46
|
+
"https://#{server_path}:#{port}"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'redgreen'
|
4
|
+
require 'rr'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
8
|
+
require 'casual'
|
9
|
+
|
10
|
+
class Test::Unit::TestCase
|
11
|
+
include RR::Adapters::TestUnit
|
12
|
+
end
|
data/test/test_casual.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestCasual < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@client = Casual::Client.new(:server_path => 'localhost',
|
7
|
+
:port => 443,
|
8
|
+
:callback_url => 'http://localhost')
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_authorization_url
|
12
|
+
assert_equal @client.authorization_url,
|
13
|
+
"https://localhost:443/login?service=http://localhost"
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_user_login_success
|
17
|
+
mock(@client).authenticate_ticket.with('GOLDEN_TICKET_LOL') {
|
18
|
+
'<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">'+
|
19
|
+
'<cas:authenticationSuccess><cas:user>holman</cas:user></cas:authenticationSuccess>'+
|
20
|
+
'</cas:serviceResponse>'
|
21
|
+
}
|
22
|
+
assert_equal @client.user_login('GOLDEN_TICKET_LOL'), 'holman'
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_user_login_fail
|
26
|
+
mock(@client).authenticate_ticket.with('GOLDEN_TICKET_FAIL') {
|
27
|
+
'<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">'+
|
28
|
+
'<cas:authenticationFailure code="INVALID_TICKET">Ticket \'GOLDEN_TICKET_FAIL\' not recognized.'+
|
29
|
+
'</cas:authenticationFailure></cas:serviceResponse>'
|
30
|
+
}
|
31
|
+
assert_equal @client.user_login('GOLDEN_TICKET_FAIL'), nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_authenticate_success
|
35
|
+
connection_mock = mock('').post.with_any_args {
|
36
|
+
[Net::HTTPSuccess.new('','200',''), '<div class="messagebox confirmation">You have successfully logged in.</div>']
|
37
|
+
}
|
38
|
+
mock(@client).connection { connection_mock }
|
39
|
+
mock(@client).acquire_ticket { 'a_ticket' }
|
40
|
+
assert_equal @client.authenticate('holman','lolsecret'), 'holman'
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: casual
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Zach Holman
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-31 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: nokogiri
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description: A tiny CAS client for Ruby
|
33
|
+
email: github.com@zachholman.com
|
34
|
+
executables: []
|
35
|
+
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files:
|
39
|
+
- LICENSE
|
40
|
+
- README.markdown
|
41
|
+
files:
|
42
|
+
- .document
|
43
|
+
- .gitignore
|
44
|
+
- LICENSE
|
45
|
+
- README.markdown
|
46
|
+
- Rakefile
|
47
|
+
- VERSION
|
48
|
+
- casual.gemspec
|
49
|
+
- lib/casual.rb
|
50
|
+
- test/helper.rb
|
51
|
+
- test/test_casual.rb
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://github.com/holman/casual
|
54
|
+
licenses: []
|
55
|
+
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options:
|
58
|
+
- --charset=UTF-8
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.3.6
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: A tiny CAS client for Ruby
|
82
|
+
test_files:
|
83
|
+
- test/helper.rb
|
84
|
+
- test/test_casual.rb
|