verge 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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ doc/*
6
+ .yardoc
7
+ pkg
8
+ *.sqlite3
9
+ log/*
10
+ tmp/*
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Adam Elliot
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,17 @@
1
+ = Verge
2
+
3
+ Lightweight centralized authentications system.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (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)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2009 Adam Elliot. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "verge"
8
+ gem.summary = %Q{Lightweight centralized authentication system built on Sinatra}
9
+ gem.description = %Q{Simple system that grants trusted sites tokens if users have successfully authenticated. So they are free to interact with each other securely.}
10
+ gem.email = "adam@wartube.com"
11
+ gem.homepage = "http://github.com/adamelliot/verge"
12
+ gem.authors = ["Adam Elliot"]
13
+ gem.add_dependency "sinatra"
14
+ gem.add_dependency "datamapper"
15
+ gem.add_dependency "bcrypt-ruby"
16
+ gem.add_dependency "activesupport"
17
+ gem.add_development_dependency "rspec"
18
+ gem.add_development_dependency "factory_girl"
19
+ gem.add_development_dependency "rack-test"
20
+ gem.add_development_dependency "do_sqlite3"
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
+ end
26
+
27
+ require 'spec/rake/spectask'
28
+ Spec::Rake::SpecTask.new(:spec) do |spec|
29
+ spec.spec_opts = %W{--options \"#{File.dirname(__FILE__)}/spec/spec.opts\"}
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.spec_files = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
35
+ spec.spec_opts = %W{--options \"#{File.dirname(__FILE__)}/spec/spec.opts\"}
36
+ spec.libs << 'lib' << 'spec'
37
+ spec.pattern = 'spec/**/*_spec.rb'
38
+ spec.rcov = true
39
+ spec.rcov_opts = lambda do
40
+ IO.readlines("#{File.dirname(__FILE__)}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
41
+ end
42
+ end
43
+
44
+ task :spec => :check_dependencies
45
+
46
+ begin
47
+ require 'reek/rake_task'
48
+ Reek::RakeTask.new do |t|
49
+ t.fail_on_error = true
50
+ t.verbose = false
51
+ t.source_files = 'lib/**/*.rb'
52
+ end
53
+ rescue LoadError
54
+ task :reek do
55
+ abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
56
+ end
57
+ end
58
+
59
+ task :default => :spec
60
+
61
+ begin
62
+ require 'yard'
63
+ YARD::Rake::YardocTask.new
64
+ rescue LoadError
65
+ task :yardoc do
66
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
67
+ end
68
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,15 @@
1
+ require 'digest/sha2'
2
+
3
+ module Verge
4
+ module Crypto
5
+ extend self
6
+
7
+ def token # nodoc #
8
+ Digest::SHA512.hexdigest((1..10).collect{ rand.to_s }.join + Time.now.usec.to_s)
9
+ end
10
+
11
+ def digest(*values) # nodoc #
12
+ Digest::SHA512.hexdigest values.join
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,74 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+
4
+ module Verge
5
+ module Server
6
+ class Base < Sinatra::Base
7
+ enable :logging
8
+ set :root, File.dirname(__FILE__)
9
+
10
+ configure :development do
11
+ enable :dump_errors
12
+ end
13
+
14
+ # Request from clients (browers generally) to authenticate with username
15
+ # and password. Returns a token that should be sent back to the site
16
+ # along with the login passed here to be verified by the site
17
+ # as allowed to login.
18
+ get '/auth' do
19
+ extract_site
20
+
21
+ user = User.authenticate(params[:login], params[:password])
22
+ halt 401, "Bad user." if user.nil?
23
+
24
+ set_cookie_for_user(user)
25
+ user.token.value
26
+ end
27
+
28
+ get '/token.js' do
29
+ @token = request.cookies["token"]
30
+ @login = request.cookies["login"]
31
+
32
+ erb 'token.js'.to_sym unless @token.nil? || @token.blank? || @login.nil? || @login.blank?
33
+ end
34
+
35
+ # Creates user accounts
36
+ post '/create' do
37
+ extract_site
38
+
39
+ user = User.new(:login => params[:login], :password => params[:password])
40
+ halt 400, "Could not create user." unless user.save
41
+
42
+ # TODO: Make user activation not manditory, for now ther is no activation mechanism
43
+ user.activate!
44
+
45
+ user.token.value
46
+ end
47
+
48
+ # Verifies if a token passed to a site is valid and checks that it
49
+ # properly matches the user requesting it.
50
+ #
51
+ # This is called from the sites themselves to verify that the token
52
+ # being passed from the client isn't spoofed and can be trusted to
53
+ # be the user they say they are.
54
+ get '/verify/:token' do |token|
55
+ signed_token = extract_site.signed_tokens.first(:value => token)
56
+ halt 404, "Token not found." if signed_token.nil?
57
+ end
58
+
59
+ private
60
+
61
+ def extract_site # nodoc #
62
+ site = Site.find_by_url(request.referer)
63
+ (site.nil? && halt(401, "Not a valid site.")) || site
64
+ end
65
+
66
+ def set_cookie_for_user(user) # nodoc #
67
+ response.set_cookie("token", {
68
+ :value => user.token.value,
69
+ :path => '/'
70
+ })
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,156 @@
1
+ require 'dm-core'
2
+ require 'dm-aggregates'
3
+ require 'dm-validations'
4
+ require 'dm-types'
5
+ require 'dm-timestamps'
6
+
7
+ require 'activesupport'
8
+
9
+ DataMapper::Logger.new("#{Dir.pwd}/../log/dm.log", :debug)
10
+ DataMapper::setup(:default, ENV['DATABASE_URL'] || "sqlite3:///#{Dir.pwd}/../db.sqlite3")
11
+
12
+ module Verge
13
+ module Server
14
+ class User
15
+ include DataMapper::Resource
16
+
17
+ property :id, Serial, :key => true
18
+ property :login, String, :nullable => false, :length => 1..255
19
+ property :password, BCryptHash
20
+ property :activated, Boolean, :default => false, :nullable => false
21
+ property :expiry, DateTime, :default => lambda { DateTime.now + 1.day }
22
+
23
+ has n, :tokens, :expiry.gt => DateTime.now
24
+
25
+ validates_is_unique :login
26
+
27
+ before :destroy, :destroy_tokens
28
+
29
+ # Generates a new token for this user.
30
+ def generate_token(expiry = nil)
31
+ tokens.create(expiry && {:expiry => expiry} || {})
32
+ end
33
+
34
+ # Returns a valid token for this user. If no tokens exist on is created
35
+ def token
36
+ tokens.count > 0 ? tokens.first : generate_token
37
+ end
38
+
39
+ # Marks this user as valid. Invalid users will be destroyed after their
40
+ # expiry passes.
41
+ def activate!
42
+ activated = true
43
+ expiry = nil
44
+ save
45
+ end
46
+
47
+ # Attempts to find a user based on the credentials passed.
48
+ def self.authenticate(login, password)
49
+ u = User.first(:login => login)
50
+ (u.nil? || u.password != password) && nil || u
51
+ end
52
+
53
+ # Removes expired users
54
+ def self.remove_expired_users
55
+ User.all(:expiry.lt => DateTime.now).destroy
56
+ end
57
+
58
+ private
59
+
60
+ def destroy_tokens
61
+ tokens.all.destroy
62
+ end
63
+ end
64
+
65
+ class SignedToken
66
+ include DataMapper::Resource
67
+
68
+ property :id, Serial, :key => true
69
+ property :value, String, :length => 128..128, :nullable => false
70
+
71
+ belongs_to :token
72
+ belongs_to :site
73
+
74
+ validates_is_unique :value
75
+ end
76
+
77
+ class Token
78
+ TERMINAL_EPOCH = DateTime.new(4000) # Distant future
79
+
80
+ include DataMapper::Resource
81
+
82
+ property :id, Serial, :key => true
83
+ property :value, String, :length => 128..128, :default => lambda { Verge::Crypto.token }
84
+ property :expiry, DateTime, :nullable => false, :default => TERMINAL_EPOCH
85
+
86
+ belongs_to :user
87
+ has n, :signed_tokens
88
+
89
+ before :destroy, :destroy_signed_tokens
90
+ after :create, :sign
91
+
92
+ private
93
+
94
+ def sign # nodoc #
95
+ Site.all.each do |site|
96
+ site.sign_token(self)
97
+ end
98
+ end
99
+
100
+ def destroy_signed_tokens # nodoc #
101
+ signed_tokens.destroy
102
+ end
103
+ end
104
+
105
+ class Site
106
+ include DataMapper::Resource
107
+
108
+ property :id, Serial, :key => true
109
+ property :domain, String, :length => 3..300
110
+ property :signature, String, :length => 128..128, :default => lambda { Verge::Crypto.token }
111
+
112
+ has n, :signed_tokens
113
+
114
+ validates_is_unique :domain
115
+ validates_is_unique :signature
116
+
117
+ before :destroy, :destroy_signed_tokens
118
+ after :create, :sign_tokens
119
+
120
+ # Prepends this sites token to the string list and runs a digest over
121
+ # the new string.
122
+ def sign(*args)
123
+ Verge::Crypto.digest(signature, args.join)
124
+ end
125
+
126
+ # Takes a token for a user and signs it creating a new hash
127
+ def sign_token(token)
128
+ signed_tokens.create(:value => sign(token.user.login, token.value), :token => token)
129
+ end
130
+
131
+ # Searchs all the sites for ones that match the protocol and domain
132
+ # EG:
133
+ # "http://verge.example.com/some/path?id=1" will match
134
+ # "verge.example.com"
135
+ def self.find_by_url(url)
136
+ return nil if url.nil?
137
+ domain = url[/^([A-Za-z\d]*(:\/\/)){0,1}([^\/]*)/, 3]
138
+ Site.first(:domain => domain)
139
+ end
140
+
141
+ private
142
+
143
+ def sign_tokens # nodoc #
144
+ Token.all(:expiry.gt => DateTime.now).each do |token|
145
+ sign_token(token)
146
+ end
147
+ end
148
+
149
+ def destroy_signed_tokens # nodoc #
150
+ signed_tokens.destroy
151
+ end
152
+ end
153
+
154
+ DataMapper.auto_migrate!
155
+ end
156
+ end
@@ -0,0 +1,29 @@
1
+ (function() {
2
+ function announceToken() {
3
+ var login = "<%= @login %>";
4
+ var token = "<%= @token %>";
5
+
6
+ // For now we'll just write the server's token to the console, in the
7
+ // future we'll need to actually do something with it.
8
+ if (console) {
9
+ console.log("Login: " + login);
10
+ console.log("Token: " + token);
11
+ }
12
+ }
13
+
14
+ (function() {
15
+ if (document.addEventListener) {
16
+ document.addEventListener("DOMContentLoaded", function() {
17
+ document.removeEventListener("DOMContentLoaded", arguments.callee, false);
18
+ announceToken();
19
+ }, false);
20
+ } else if (document.attachEvent) {
21
+ document.attachEvent("onreadystatechange", function() {
22
+ if (document.readyState == "complete") {
23
+ document.detachEvent("onreadystatechange", argument.callee);
24
+ announceToken();
25
+ }
26
+ });
27
+ }
28
+ })();
29
+ })();
data/lib/verge.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+
3
+ module Verge
4
+ autoload :Crypto, "verge/crypto"
5
+
6
+ module Server
7
+ autoload :Base, "verge/server/base"
8
+
9
+ autoload :User, "verge/server/models"
10
+ autoload :SignedToken, "verge/server/models"
11
+ autoload :Token, "verge/server/models"
12
+ autoload :Site, "verge/server/models"
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Verge::Crypto do
4
+ it "returns a sha512 token" do
5
+ Verge::Crypto.token.length.should == 128
6
+ end
7
+
8
+ it "creates a hash for multiple values entered" do
9
+ Verge::Crypto.digest("some", "values").length.should == 128
10
+ end
11
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,17 @@
1
+ Factory.sequence(:login) { |n| "verge-#{n}" }
2
+ Factory.sequence(:domain) { |n| "site-#{n}.com" }
3
+
4
+ Factory.define(:user, :class => Verge::Server::User) do |u|
5
+ u.login { Factory.next(:login) }
6
+ u.password '0rbital'
7
+ end
8
+
9
+ Factory.define(:site, :class => Verge::Server::Site) do |s|
10
+ s.domain { Factory.next(:domain) }
11
+ end
12
+
13
+ Factory.define(:signed_token, :class => Verge::Server::SignedToken) do |s|
14
+ s.token_id 1
15
+ s.site_id 1
16
+ s.value { Verge::Crypto.token }
17
+ end
@@ -0,0 +1,148 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Verge::Server::User do
4
+ before :each do
5
+ Verge::Server::Token.all.destroy!
6
+ Verge::Server::User.all.destroy!
7
+ @user = Factory(:user)
8
+ end
9
+
10
+ it "doesn't allow duplicate logins" do
11
+ Factory(:user, :login => @user.login).should_not be_valid
12
+ end
13
+
14
+ it "finds user when provided valid credentials" do
15
+ Verge::Server::User.authenticate(@user.login, "0rbital").should_not be_nil
16
+ end
17
+
18
+ it "returns nil if no user is found for credentials" do
19
+ Verge::Server::User.authenticate("nobody", "---").should be_nil
20
+ end
21
+
22
+ it "creates a token with an expiry" do
23
+ expiry = DateTime.now + 100
24
+ @user.generate_token(expiry)
25
+ @user.tokens.first.expiry.should eql(expiry)
26
+ end
27
+
28
+ it "destroys any tokens that belong to it when destroyed" do
29
+ @user.token
30
+ @user.destroy
31
+ Verge::Server::Token.count.should eql(0)
32
+ end
33
+
34
+ it "valid token returns an existing token when one's been created" do
35
+ @user.generate_token
36
+ count = @user.tokens.count
37
+ @user.token
38
+
39
+ @user.tokens.count.should eql(count)
40
+ end
41
+
42
+ it "valid token creates a new token when none exist" do
43
+ count = @user.tokens.count
44
+ @user.token
45
+
46
+ @user.tokens.count.should eql(count + 1)
47
+ end
48
+
49
+ it "starts out as an inactive user and has an expiry" do
50
+ @user.activated.should be_false
51
+ @user.expiry.should >= DateTime.now + 4.minutes
52
+ end
53
+
54
+ it "will mark the model as activated and remove the expiry" do
55
+ @user.activate!
56
+ end
57
+
58
+ it "removes any uses that have expired" do
59
+ Factory(:user, :expiry => 1.minute.ago)
60
+ count = Verge::Server::User.count
61
+ Verge::Server::User.remove_expired_users
62
+ Verge::Server::User.count.should == (count - 1)
63
+ end
64
+ end
65
+
66
+ describe Verge::Server::SignedToken do
67
+ before :each do
68
+ @signed_token = Factory(:signed_token)
69
+ end
70
+
71
+ it "doesn't allow duplicate signatures" do
72
+ Factory(:signed_token, :value => @signed_token.value).should_not be_valid
73
+ end
74
+ end
75
+
76
+ describe Verge::Server::Token do
77
+ before :each do
78
+ Verge::Server::SignedToken.all.destroy!
79
+ Verge::Server::Token.all.destroy!
80
+ Factory(:site)
81
+ @user = Factory(:user)
82
+
83
+ @token = Verge::Server::Token.create(:user_id => @user.id)
84
+ end
85
+
86
+ it "has a valid token" do
87
+ @token.value.length.should eql(128)
88
+ end
89
+
90
+ it "has a user_id" do
91
+ new_token = Verge::Server::Token.new
92
+ new_token.user_id.should be_nil
93
+ new_token.should_not be_valid
94
+ end
95
+
96
+ it "destroys any signed tokens that belong to it when destroyed" do
97
+ @token.destroy
98
+ Verge::Server::SignedToken.count.should eql(0)
99
+ end
100
+
101
+ it "automatically creates signed tokens for each site when created" do
102
+ Verge::Server::Site.count.should eql(Verge::Server::SignedToken.count)
103
+ end
104
+ end
105
+
106
+ describe Verge::Server::Site do
107
+ before :each do
108
+ Verge::Server::Site.all.destroy!
109
+ Verge::Server::User.all.destroy!
110
+ Verge::Server::Token.all.destroy!
111
+ Verge::Server::SignedToken.all.destroy!
112
+
113
+ @user = Factory(:user)
114
+ @site = Factory(:site)
115
+ end
116
+
117
+ it "returns valid token after signing token" do
118
+ @site.sign_token(Verge::Server::User.first.token).value.length.should == 128
119
+ end
120
+
121
+ it "destroys any signed tokens that belong to it when destroyed" do
122
+ Verge::Server::Token.create(:user_id => @user.id)
123
+ @site.signed_tokens.destroy
124
+ Verge::Server::SignedToken.count.should eql(0)
125
+ end
126
+
127
+ it "signs any tokens that haven't expired when created" do
128
+ @user.token
129
+ Verge::Server::SignedToken.count.should eql(Verge::Server::Site.count)
130
+ # Factory(:site) uses create! which will bypass the after hook
131
+ Factory.build(:site).save.should be_true
132
+ Verge::Server::SignedToken.count.should eql(Verge::Server::Site.count)
133
+ end
134
+
135
+ it "returns a site when the domain and protocol match" do
136
+ site1 = Factory(:site)
137
+ site2 = Verge::Server::Site.find_by_url("http://#{site1.domain}/some/other/path?junk=10&true=false")
138
+ site2.should_not be_nil
139
+ site2.domain.should eql(site1.domain)
140
+ end
141
+
142
+ it "should create a valid signed token when signing" do
143
+ @user.token.should_not be_nil
144
+ Verge::Server::SignedToken.count.should eql(1)
145
+ signature = Verge::Crypto.digest(@site.signature, @user.login, @user.token.value)
146
+ Verge::Server::SignedToken.first.value.should == signature
147
+ end
148
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1,2 @@
1
+ --exclude "spec/*,/Library/*"
2
+ -T
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --loadby mtime
3
+ --reverse
4
+ -fs
@@ -0,0 +1,18 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'verge'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'rack/test'
7
+ require 'factory_girl'
8
+
9
+ require File.expand_path(File.dirname(__FILE__)) + '/factories'
10
+
11
+ Spec::Runner.configure do |config|
12
+ config.include Rack::Test::Methods
13
+
14
+ # Add an app method for RSpec
15
+ def app
16
+ Rack::Lint.new(Verge::Server::Base.new)
17
+ end
18
+ end
@@ -0,0 +1,128 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ module VergeSpecHelper
4
+ def valid_auth_request_for_user(user)
5
+ {:login => user.login, :password => "0rbital"}
6
+ end
7
+
8
+ def new_user_credentials_for_site(site)
9
+ login = 'new-verge-user'
10
+ {:login => login, :password => '0rbital', :signature => site.sign(login)}
11
+ end
12
+ end
13
+
14
+ describe Verge::Server do
15
+ include VergeSpecHelper
16
+
17
+ before :each do
18
+ @site = Factory(:site)
19
+ header("Referer", @site.domain)
20
+ end
21
+
22
+ describe "GET to /token.js" do
23
+ it "echos cookie back in javascript" do
24
+ login = "astro"
25
+ token = "bombastic"
26
+
27
+ set_cookie("login=#{login}")
28
+ set_cookie("token=#{token}")
29
+
30
+ get '/token.js'
31
+ last_response.body.should =~ /#{login}/
32
+ last_response.body.should =~ /#{token}/
33
+ end
34
+
35
+ it "echos nothing if no cookies are sent" do
36
+ get '/token.js'
37
+ last_response.body.should == ""
38
+ last_response.should be_ok
39
+ end
40
+
41
+ it "echos nothing if login is blank" do
42
+ set_cookie("login=")
43
+ set_cookie("token=a-token")
44
+
45
+ get '/token.js'
46
+ last_response.body.should == ""
47
+ last_response.should be_ok
48
+ end
49
+
50
+ it "echos nothing if login is blank" do
51
+ set_cookie("login=a-login")
52
+ set_cookie("token=")
53
+
54
+ get '/token.js'
55
+ last_response.body.should == ""
56
+ last_response.should be_ok
57
+ end
58
+ end
59
+
60
+
61
+ describe 'GET to /auth' do
62
+ before :each do
63
+ @user = Factory(:user)
64
+ end
65
+
66
+ it 'fails with empty request' do
67
+ get '/auth'
68
+ last_response.status.should == 401
69
+ end
70
+
71
+ it 'returns a code when valid' do
72
+ get '/auth', valid_auth_request_for_user(@user)
73
+ last_response.body.should == @user.token.value
74
+ end
75
+
76
+ it 'sets a cookie on success' do
77
+ get '/auth', valid_auth_request_for_user(@user)
78
+ last_response.headers["Set-Cookie"].should == "token=#{@user.token.value}; path=/"
79
+ end
80
+ end
81
+
82
+ describe "POST to /create" do
83
+ before :each do
84
+ Verge::Server::User.all.destroy!
85
+ end
86
+
87
+ it "fails if site not found" do
88
+ header("Referer", "BAD://SITE")
89
+ post '/create'
90
+
91
+ last_response.status.should == 401
92
+ end
93
+
94
+ it "creates a new user" do
95
+ post '/create', new_user_credentials_for_site(@site)
96
+ last_response.should be_ok
97
+ last_response.body.should == Verge::Server::User.first.token.value
98
+ end
99
+ end
100
+
101
+ describe 'GET to /verify/:token' do
102
+ before :each do
103
+ @user = Factory(:user)
104
+ @signed_token = @user.token.signed_tokens.first(:site_id => @site.id)
105
+
106
+ header("Referer", @site.domain)
107
+ end
108
+
109
+ it "fails if no regisered site is found" do
110
+ header("Referer", "BAD://SITE")
111
+ get "/verify/anything"
112
+
113
+ last_response.status.should == 401
114
+ end
115
+
116
+ it "fails if token can't be found" do
117
+ get "/verify/anything"
118
+
119
+ last_response.status.should == 404
120
+ end
121
+
122
+ it "succeeds if the token is valid" do
123
+ get "/verify/#{@signed_token.value}"
124
+
125
+ last_response.should be_ok
126
+ end
127
+ end
128
+ end
data/verge.gemspec ADDED
@@ -0,0 +1,87 @@
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{verge}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Adam Elliot"]
12
+ s.date = %q{2009-10-20}
13
+ s.description = %q{Simple system that grants trusted sites tokens if users have successfully authenticated. So they are free to interact with each other securely.}
14
+ s.email = %q{adam@wartube.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
+ "lib/verge.rb",
27
+ "lib/verge/crypto.rb",
28
+ "lib/verge/server/base.rb",
29
+ "lib/verge/server/models.rb",
30
+ "lib/verge/server/views/token.js.erb",
31
+ "spec/crypto_spec.rb",
32
+ "spec/factories.rb",
33
+ "spec/models_spec.rb",
34
+ "spec/rcov.opts",
35
+ "spec/spec.opts",
36
+ "spec/spec_helper.rb",
37
+ "spec/verge_spec.rb",
38
+ "verge.gemspec"
39
+ ]
40
+ s.homepage = %q{http://github.com/adamelliot/verge}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.5}
44
+ s.summary = %q{Lightweight centralized authentication system built on Sinatra}
45
+ s.test_files = [
46
+ "spec/crypto_spec.rb",
47
+ "spec/factories.rb",
48
+ "spec/models_spec.rb",
49
+ "spec/spec_helper.rb",
50
+ "spec/verge_spec.rb"
51
+ ]
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58
+ s.add_runtime_dependency(%q<sinatra>, [">= 0"])
59
+ s.add_runtime_dependency(%q<datamapper>, [">= 0"])
60
+ s.add_runtime_dependency(%q<bcrypt-ruby>, [">= 0"])
61
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
62
+ s.add_development_dependency(%q<rspec>, [">= 0"])
63
+ s.add_development_dependency(%q<factory_girl>, [">= 0"])
64
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
65
+ s.add_development_dependency(%q<do_sqlite3>, [">= 0"])
66
+ else
67
+ s.add_dependency(%q<sinatra>, [">= 0"])
68
+ s.add_dependency(%q<datamapper>, [">= 0"])
69
+ s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
70
+ s.add_dependency(%q<activesupport>, [">= 0"])
71
+ s.add_dependency(%q<rspec>, [">= 0"])
72
+ s.add_dependency(%q<factory_girl>, [">= 0"])
73
+ s.add_dependency(%q<rack-test>, [">= 0"])
74
+ s.add_dependency(%q<do_sqlite3>, [">= 0"])
75
+ end
76
+ else
77
+ s.add_dependency(%q<sinatra>, [">= 0"])
78
+ s.add_dependency(%q<datamapper>, [">= 0"])
79
+ s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
80
+ s.add_dependency(%q<activesupport>, [">= 0"])
81
+ s.add_dependency(%q<rspec>, [">= 0"])
82
+ s.add_dependency(%q<factory_girl>, [">= 0"])
83
+ s.add_dependency(%q<rack-test>, [">= 0"])
84
+ s.add_dependency(%q<do_sqlite3>, [">= 0"])
85
+ end
86
+ end
87
+
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: verge
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Adam Elliot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-20 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: datamapper
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: bcrypt-ruby
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: activesupport
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: factory_girl
67
+ type: :development
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: rack-test
77
+ type: :development
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: do_sqlite3
87
+ type: :development
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
95
+ description: Simple system that grants trusted sites tokens if users have successfully authenticated. So they are free to interact with each other securely.
96
+ email: adam@wartube.com
97
+ executables: []
98
+
99
+ extensions: []
100
+
101
+ extra_rdoc_files:
102
+ - LICENSE
103
+ - README.rdoc
104
+ files:
105
+ - .document
106
+ - .gitignore
107
+ - LICENSE
108
+ - README.rdoc
109
+ - Rakefile
110
+ - VERSION
111
+ - lib/verge.rb
112
+ - lib/verge/crypto.rb
113
+ - lib/verge/server/base.rb
114
+ - lib/verge/server/models.rb
115
+ - lib/verge/server/views/token.js.erb
116
+ - spec/crypto_spec.rb
117
+ - spec/factories.rb
118
+ - spec/models_spec.rb
119
+ - spec/rcov.opts
120
+ - spec/spec.opts
121
+ - spec/spec_helper.rb
122
+ - spec/verge_spec.rb
123
+ - verge.gemspec
124
+ has_rdoc: true
125
+ homepage: http://github.com/adamelliot/verge
126
+ licenses: []
127
+
128
+ post_install_message:
129
+ rdoc_options:
130
+ - --charset=UTF-8
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: "0"
138
+ version:
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: "0"
144
+ version:
145
+ requirements: []
146
+
147
+ rubyforge_project:
148
+ rubygems_version: 1.3.5
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: Lightweight centralized authentication system built on Sinatra
152
+ test_files:
153
+ - spec/crypto_spec.rb
154
+ - spec/factories.rb
155
+ - spec/models_spec.rb
156
+ - spec/spec_helper.rb
157
+ - spec/verge_spec.rb