verge 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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