gatekeeper 0.1.0
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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +20 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/gatekeeper.gemspec +58 -0
- data/lib/gatekeeper.rb +15 -0
- data/lib/gatekeeper/helpers/rack.rb +43 -0
- data/lib/gatekeeper/middleware.rb +17 -0
- data/lib/gatekeeper/sso.rb +63 -0
- data/spec/gatekeeper_spec.rb +61 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +79 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Chris Dinn
|
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.rdoc
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
= Gatekeeper
|
2
|
+
|
3
|
+
Gatekeeper can connect any Rack-compatible application to a Hot Ink SSO server. It allows you to easily verify the identity of a user against Hot Ink's
|
4
|
+
user information database. It makes some basic information about the user available to you application.
|
5
|
+
|
6
|
+
Gatekeeper is largely a rewrite of Hancock-Client (http://github.com/atmos/hancock-client). The functionality is different but the spirit is the same.
|
7
|
+
|
8
|
+
== Note on Patches/Pull Requests
|
9
|
+
|
10
|
+
* Fork the project.
|
11
|
+
* Make your feature addition or bug fix.
|
12
|
+
* Add specs for it. This is important so I don't break it in a
|
13
|
+
future version unintentionally.
|
14
|
+
* Commit, do not mess with rakefile, version, or history.
|
15
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
16
|
+
* Send me a pull request. Bonus points for topic branches.
|
17
|
+
|
18
|
+
== Copyright
|
19
|
+
|
20
|
+
Copyright (c) 2010 Chris Dinn. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "gatekeeper"
|
8
|
+
gem.summary = "Connects any Rack-compatible app to a Hot Ink single sign on server."
|
9
|
+
gem.description = "Connects any Rack-compatible app to a Hot Ink single sign on server."
|
10
|
+
gem.email = "chrisgdinn@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/chrisdinn/gatekeeper"
|
12
|
+
gem.authors = ["Chris Dinn"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
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 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
40
|
+
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = "gatekeeper #{version}"
|
43
|
+
rdoc.rdoc_files.include('README*')
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/gatekeeper.gemspec
ADDED
@@ -0,0 +1,58 @@
|
|
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{gatekeeper}
|
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 = ["Chris Dinn"]
|
12
|
+
s.date = %q{2010-01-12}
|
13
|
+
s.description = %q{Connects any Rack-compatible app to a Hot Ink single sign on server.}
|
14
|
+
s.email = %q{chrisgdinn@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"gatekeeper.gemspec",
|
27
|
+
"lib/gatekeeper.rb",
|
28
|
+
"lib/gatekeeper/helpers/rack.rb",
|
29
|
+
"lib/gatekeeper/middleware.rb",
|
30
|
+
"lib/gatekeeper/sso.rb",
|
31
|
+
"spec/gatekeeper_spec.rb",
|
32
|
+
"spec/spec.opts",
|
33
|
+
"spec/spec_helper.rb"
|
34
|
+
]
|
35
|
+
s.homepage = %q{http://github.com/chrisdinn/gatekeeper}
|
36
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
s.rubygems_version = %q{1.3.5}
|
39
|
+
s.summary = %q{Connects any Rack-compatible app to a Hot Ink single sign on server.}
|
40
|
+
s.test_files = [
|
41
|
+
"spec/gatekeeper_spec.rb",
|
42
|
+
"spec/spec_helper.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
50
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
data/lib/gatekeeper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
gem 'sinatra', '~>0.9.2'
|
2
|
+
require 'sinatra/base'
|
3
|
+
|
4
|
+
gem 'ruby-openid', '>=2.1.6'
|
5
|
+
require 'openid'
|
6
|
+
require 'openid/store/filesystem'
|
7
|
+
|
8
|
+
gem 'rack-openid', '>=0.2'
|
9
|
+
require 'rack/openid'
|
10
|
+
|
11
|
+
require 'tmpdir'
|
12
|
+
|
13
|
+
require File.dirname(__FILE__)+'/gatekeeper/helpers/rack'
|
14
|
+
require File.dirname(__FILE__)+'/gatekeeper/sso'
|
15
|
+
require File.dirname(__FILE__)+'/gatekeeper/middleware'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Gatekeeper
|
2
|
+
module Client
|
3
|
+
module Helpers
|
4
|
+
module Rack
|
5
|
+
def sso_logged_in?
|
6
|
+
session[:sso] && sso_user_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def sso_login_as(user_id, sreg_params)
|
10
|
+
session.delete(:last_oidreq)
|
11
|
+
session.delete('OpenID::Consumer::last_requested_endpoint')
|
12
|
+
session.delete('OpenID::Consumer::DiscoveredServices::OpenID::Consumer::')
|
13
|
+
|
14
|
+
session[:sso] ||= { }
|
15
|
+
session[:sso][:user_id] = user_id
|
16
|
+
sreg_params.each { |key, value| session[:sso][key.to_sym] = value.to_s }
|
17
|
+
end
|
18
|
+
|
19
|
+
def sso_user_id
|
20
|
+
session[:sso][:user_id]
|
21
|
+
end
|
22
|
+
|
23
|
+
def sso_user_email
|
24
|
+
session[:sso][:email]
|
25
|
+
end
|
26
|
+
|
27
|
+
def absolute_url(suffix = nil)
|
28
|
+
port_part = case request.scheme
|
29
|
+
when "http"
|
30
|
+
request.port == 80 ? "" : ":#{request.port}"
|
31
|
+
when "https"
|
32
|
+
request.port == 443 ? "" : ":#{request.port}"
|
33
|
+
end
|
34
|
+
"#{request.scheme}://#{request.host}#{port_part}#{suffix}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def excluded_path?
|
38
|
+
options.exclude_paths && options.exclude_paths.include?(request.path_info)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Gatekeeper
|
2
|
+
module Client
|
3
|
+
class Middleware < Sinatra::Base
|
4
|
+
enable :raise_errors
|
5
|
+
disable :show_exceptions
|
6
|
+
|
7
|
+
set :sso_url, nil
|
8
|
+
set :exclude_paths, nil
|
9
|
+
|
10
|
+
def sso_url=(url)
|
11
|
+
options.sso_url = url
|
12
|
+
end
|
13
|
+
|
14
|
+
register ::Gatekeeper::Client::SSO
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Gatekeeper
|
2
|
+
module Client
|
3
|
+
module SSO
|
4
|
+
def self.registered(app)
|
5
|
+
app.use(Rack::OpenID, OpenID::Store::Filesystem.new("#{Dir.tmpdir}/openid"))
|
6
|
+
app.helpers Gatekeeper::Client::Helpers::Rack
|
7
|
+
|
8
|
+
app.get '/sso/login' do
|
9
|
+
if contact_id = params['id']
|
10
|
+
response['WWW-Authenticate'] = Rack::OpenID.build_header(
|
11
|
+
:identifier => "#{options.sso_url}/users/#{contact_id}",
|
12
|
+
:trust_root => absolute_url('/sso/login')
|
13
|
+
)
|
14
|
+
throw :halt, [401, 'got openid?']
|
15
|
+
elsif openid = request.env["rack.openid.response"]
|
16
|
+
if openid.status == :success
|
17
|
+
if contact_id = openid.display_identifier.split("/").last
|
18
|
+
sreg_params = openid.message.get_args("http://openid.net/extensions/sreg/1.1")
|
19
|
+
sso_login_as(contact_id, sreg_params)
|
20
|
+
|
21
|
+
if session['sso_return_to']
|
22
|
+
begin
|
23
|
+
return_url = URI.parse(session['sso_return_to'])
|
24
|
+
|
25
|
+
unless return_url.host==request.host
|
26
|
+
user_token = UserToken.create!(:user_id => sso_user_id)
|
27
|
+
if return_url.query==nil
|
28
|
+
return_url.query = "user_token=#{user_token.token}"
|
29
|
+
else
|
30
|
+
return_url.query = "user_token=#{user_token.token}&#{return_url.query}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
redirect return_url.to_s
|
35
|
+
rescue
|
36
|
+
redirect '/'
|
37
|
+
ensure
|
38
|
+
session['sso_return_to'] = nil
|
39
|
+
end
|
40
|
+
else
|
41
|
+
redirect '/'
|
42
|
+
end
|
43
|
+
|
44
|
+
else
|
45
|
+
raise "No contact could be found for #{openid.display_identifier}"
|
46
|
+
end
|
47
|
+
else
|
48
|
+
throw :halt, [503, "Error: #{openid.status}"]
|
49
|
+
end
|
50
|
+
else
|
51
|
+
session['sso_return_to'] = params[:return_to] if params[:return_to]
|
52
|
+
redirect "#{options.sso_url}/login?return_to=#{absolute_url('/sso/login')}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
app.get '/sso/logout' do
|
57
|
+
session[:sso] = nil
|
58
|
+
redirect "#{options.sso_url}/logout"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
SSO_URL = "http://ssourl.local/sso"
|
4
|
+
|
5
|
+
class TestApp < Sinatra::Base
|
6
|
+
enable :sessions
|
7
|
+
|
8
|
+
use Gatekeeper::Client::Middleware do |sso|
|
9
|
+
sso.sso_url = SSO_URL
|
10
|
+
end
|
11
|
+
|
12
|
+
get "/test" do
|
13
|
+
"success"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Gatekeeper" do
|
18
|
+
include Rack::Test::Methods
|
19
|
+
|
20
|
+
def app
|
21
|
+
TestApp
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "sso login" do
|
25
|
+
it "should defer to SSO server for authentication" do
|
26
|
+
get '/sso/login'
|
27
|
+
|
28
|
+
last_response.should be_redirect
|
29
|
+
last_response.headers['Location'].should == "#{SSO_URL}/login?return_to=http://example.org/sso/login"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should build OpenID header, when appropriate" do
|
33
|
+
get '/sso/login', :id => 1
|
34
|
+
|
35
|
+
last_response.status.should == 401
|
36
|
+
last_response.body.should == 'got openid?'
|
37
|
+
last_response.headers['WWW-Authenticate'].should == Rack::OpenID.build_header(
|
38
|
+
:identifier => "#{SSO_URL}/users/1",
|
39
|
+
:trust_root => "http://example.org/sso/login"
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should log in a user if OpenID authentication succeeds" do
|
44
|
+
checkid_response = mock('OpenID response')
|
45
|
+
message = mock('OpenID message')
|
46
|
+
|
47
|
+
checkid_response.stub!(:status).and_return(:success)
|
48
|
+
checkid_response.stub!(:display_identifier).and_return("#{SSO_URL}/users/1")
|
49
|
+
|
50
|
+
message.stub!(:get_args).with("http://openid.net/extensions/sreg/1.1").and_return({'is_admin?' => false})
|
51
|
+
checkid_response.stub!(:message).and_return(message)
|
52
|
+
|
53
|
+
get '/sso/login', {}, 'rack.openid.response' => checkid_response
|
54
|
+
|
55
|
+
last_response.should be_redirect
|
56
|
+
last_response.headers['Location'].should == "/"
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gatekeeper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Dinn
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-12 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
description: Connects any Rack-compatible app to a Hot Ink single sign on server.
|
26
|
+
email: chrisgdinn@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- .document
|
36
|
+
- .gitignore
|
37
|
+
- LICENSE
|
38
|
+
- README.rdoc
|
39
|
+
- Rakefile
|
40
|
+
- VERSION
|
41
|
+
- gatekeeper.gemspec
|
42
|
+
- lib/gatekeeper.rb
|
43
|
+
- lib/gatekeeper/helpers/rack.rb
|
44
|
+
- lib/gatekeeper/middleware.rb
|
45
|
+
- lib/gatekeeper/sso.rb
|
46
|
+
- spec/gatekeeper_spec.rb
|
47
|
+
- spec/spec.opts
|
48
|
+
- spec/spec_helper.rb
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/chrisdinn/gatekeeper
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options:
|
55
|
+
- --charset=UTF-8
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.3.5
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Connects any Rack-compatible app to a Hot Ink single sign on server.
|
77
|
+
test_files:
|
78
|
+
- spec/gatekeeper_spec.rb
|
79
|
+
- spec/spec_helper.rb
|