matthewtodd-openid-store-couchdb-chef 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +5 -0
- data/Rakefile +20 -0
- data/lib/openid-store-couchdb.rb +1 -0
- data/lib/openid/store/couchdb.rb +90 -0
- data/lib/openid/store/couchdb/association.rb +94 -0
- data/lib/openid/store/couchdb/nonce.rb +75 -0
- metadata +95 -0
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
this_rakefile_uses_shoe = <<END
|
2
|
+
----------------------------------------
|
3
|
+
Please install Shoe:
|
4
|
+
gem sources --add http://gems.github.com
|
5
|
+
gem install matthewtodd-shoe
|
6
|
+
----------------------------------------
|
7
|
+
END
|
8
|
+
|
9
|
+
begin
|
10
|
+
gem 'matthewtodd-shoe'
|
11
|
+
rescue Gem::LoadError
|
12
|
+
abort this_rakefile_uses_shoe
|
13
|
+
else
|
14
|
+
require 'shoe'
|
15
|
+
end
|
16
|
+
|
17
|
+
Shoe.tie('openid-store-couchdb-chef', '0.1.0', 'A Chef-specific OpenID store for CouchDB.') do |spec|
|
18
|
+
spec.add_dependency 'ruby-openid'
|
19
|
+
spec.add_dependency 'chef'
|
20
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'openid/store/couchdb'
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'openid'
|
2
|
+
require 'openid/store/interface'
|
3
|
+
require 'openid/store/couchdb/association'
|
4
|
+
require 'openid/store/couchdb/nonce'
|
5
|
+
|
6
|
+
module OpenID #:nodoc:
|
7
|
+
module Store #:nodoc:
|
8
|
+
|
9
|
+
# From what I can tell, the original
|
10
|
+
# openid-store-couchdb[http://github.com/b/openid-store-couchdb] isn't
|
11
|
+
# entirely complete, and there seems to be no word on the
|
12
|
+
# progress[http://tickets.opscode.com/browse/CHEF-199] of integrating it
|
13
|
+
# into Chef proper. Also, it makes use of CouchDB features I don't yet
|
14
|
+
# support in hideabed[http://github.com/matthewtodd/hideabed].
|
15
|
+
#
|
16
|
+
# Also note that OpenID is largely going
|
17
|
+
# away[http://lists.opscode.com/sympa/arc/chef-dev/2009-06/msg00001.html]
|
18
|
+
# in Chef 0.8, so we really just need a stopgap measure.
|
19
|
+
class CouchDB < Interface
|
20
|
+
def initialize(*args)
|
21
|
+
Association.create_design_document
|
22
|
+
Nonce.create_design_document
|
23
|
+
end
|
24
|
+
|
25
|
+
# Put a Association object into storage. When implementing a store,
|
26
|
+
# don't assume that there are any limitations on the character set of
|
27
|
+
# the server_url. In particular, expect to see unescaped non-url-safe
|
28
|
+
# characters in the server_url field.
|
29
|
+
def store_association(server_url, association)
|
30
|
+
if document = Association.load(server_url, association.handle)
|
31
|
+
document.association = association
|
32
|
+
document.save
|
33
|
+
else
|
34
|
+
Association.create(server_url, association)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a Association object from storage that matches the server_url.
|
39
|
+
# Returns nil if no such association is found or if the one matching
|
40
|
+
# association is expired. (Is allowed to GC expired associations when
|
41
|
+
# found.)
|
42
|
+
def get_association(server_url, handle=nil)
|
43
|
+
if document = Association.load(server_url, handle)
|
44
|
+
if document.expired?
|
45
|
+
document.destroy
|
46
|
+
nil
|
47
|
+
else
|
48
|
+
document.association
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# If there is a matching association, remove it from the store and
|
54
|
+
# return true, otherwise return false.
|
55
|
+
def remove_association(server_url, handle)
|
56
|
+
Association.destroy(server_url, handle)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Remove expired associations from the store. Not called during normal
|
60
|
+
# library operation, this method is for store admins to keep their
|
61
|
+
# storage from filling up with expired data.
|
62
|
+
def cleanup_associations
|
63
|
+
raise NotImplementedError
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return true if the nonce has not been used before, and store it for a
|
67
|
+
# while to make sure someone doesn't try to use the same value again.
|
68
|
+
# Return false if the nonce has already been used or if the timestamp is
|
69
|
+
# not current. You can use OpenID::Store::Nonce::SKEW for your timestamp
|
70
|
+
# window.
|
71
|
+
#
|
72
|
+
# +server_url+:: URL of the server from which the nonce originated
|
73
|
+
# +timestamp+:: time the nonce was created in seconds since unix epoch
|
74
|
+
# +salt+:: A random string that makes two nonces issued by a server in
|
75
|
+
# the same second unique
|
76
|
+
def use_nonce(server_url, timestamp, salt)
|
77
|
+
Nonce.create(server_url, timestamp, salt)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Remove expired nonces from the store. Discards any nonce that is old
|
81
|
+
# enough that it wouldn't pass use_nonce Not called during normal
|
82
|
+
# library operation, this method is for store admins to keep their
|
83
|
+
# storage from filling up with expired data.
|
84
|
+
def cleanup_nonces
|
85
|
+
raise NotImplementedError
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module OpenID #:nodoc:
|
2
|
+
module Store #:nodoc:
|
3
|
+
class CouchDB < Interface
|
4
|
+
|
5
|
+
class Association
|
6
|
+
DESIGN_DOCUMENT = {
|
7
|
+
'version' => 1,
|
8
|
+
'language' => 'javascript',
|
9
|
+
'views' => {}
|
10
|
+
}
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def create_design_document
|
14
|
+
Chef::CouchDB.new.create_design_document('associations', DESIGN_DOCUMENT)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(server_url, association)
|
18
|
+
new(document_name(server_url, association.handle), association).save
|
19
|
+
end
|
20
|
+
|
21
|
+
def load(server_url, handle)
|
22
|
+
Chef::CouchDB.new.load('association', document_name(server_url, handle))
|
23
|
+
rescue Net::HTTPServerException
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy(server_url, handle)
|
28
|
+
document = load(server_url, handle)
|
29
|
+
document ? document.destroy : false
|
30
|
+
end
|
31
|
+
|
32
|
+
def document_name(server_url, handle)
|
33
|
+
Base64.encode64("#{server_url}-#{handle}").chomp
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_accessor :association
|
38
|
+
|
39
|
+
def initialize(name, association, couchdb_rev = nil)
|
40
|
+
@name = name
|
41
|
+
@association = association
|
42
|
+
@couchdb_rev = couchdb_rev
|
43
|
+
@couchdb = Chef::CouchDB.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def destroy
|
47
|
+
@couchdb.delete('association', @name, @couchdb_rev)
|
48
|
+
rescue Net::HTTPServerException
|
49
|
+
false
|
50
|
+
else
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def expired?
|
55
|
+
@association.expires_in <= 0
|
56
|
+
end
|
57
|
+
|
58
|
+
def save
|
59
|
+
results = @couchdb.store('association', @name, self)
|
60
|
+
@couchdb_rev = results['rev']
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.json_create(attributes)
|
64
|
+
name = attributes['name']
|
65
|
+
handle = attributes['handle']
|
66
|
+
secret = Base64.decode64(attributes['secret'])
|
67
|
+
issued = Time.at(attributes['issued'])
|
68
|
+
lifetime = attributes['lifetime']
|
69
|
+
assoc_type = attributes['assoc_type']
|
70
|
+
couchdb_rev = attributes['_rev']
|
71
|
+
association = OpenID::Association.new(handle, secret, issued, lifetime, assoc_type)
|
72
|
+
|
73
|
+
new(name, association, couchdb_rev)
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_json(*args)
|
77
|
+
result = {
|
78
|
+
'name' => @name,
|
79
|
+
'json_class' => self.class.name,
|
80
|
+
'chef_type' => 'association',
|
81
|
+
'handle' => @association.handle,
|
82
|
+
'secret' => Base64.encode64(@association.secret).chomp,
|
83
|
+
'issued' => @association.issued.to_i,
|
84
|
+
'lifetime' => @association.lifetime,
|
85
|
+
'assoc_type' => @association.assoc_type,
|
86
|
+
}
|
87
|
+
result['_rev'] = @couchdb_rev if @couchdb_rev
|
88
|
+
result.to_json(*args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module OpenID #:nodoc:
|
2
|
+
module Store #:nodoc:
|
3
|
+
class CouchDB < Interface
|
4
|
+
|
5
|
+
class Nonce
|
6
|
+
DESIGN_DOCUMENT = {
|
7
|
+
'version' => 1,
|
8
|
+
'language' => 'javascript',
|
9
|
+
'views' => {}
|
10
|
+
}
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def create_design_document
|
14
|
+
Chef::CouchDB.new.create_design_document('nonces', DESIGN_DOCUMENT)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(server_url, timestamp, salt)
|
18
|
+
new(server_url, timestamp, salt).save
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(server_url, timestamp, salt, couchdb_rev = nil)
|
23
|
+
@server_url = server_url
|
24
|
+
@timestamp = Time.at(timestamp.to_i)
|
25
|
+
@salt = salt
|
26
|
+
@couchdb_rev = nil
|
27
|
+
@couchdb = Chef::CouchDB.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def name
|
31
|
+
[@timestamp.utc.strftime(OpenID::Nonce::TIME_FMT), Base64.encode64(@server_url).chomp, Base64.encode64(@salt).chomp].join('-')
|
32
|
+
end
|
33
|
+
|
34
|
+
def save
|
35
|
+
return false unless valid?
|
36
|
+
|
37
|
+
begin
|
38
|
+
results = @couchdb.store('nonce', name, self)
|
39
|
+
rescue Net::HTTPServerException
|
40
|
+
false
|
41
|
+
else
|
42
|
+
@couchdb_rev = results['rev']
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def valid?
|
48
|
+
OpenID::Nonce.check_timestamp(name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.json_create(attributes)
|
52
|
+
server_url = attributes['server_url']
|
53
|
+
timestamp = attributes['timestamp']
|
54
|
+
salt = attributes['salt']
|
55
|
+
couchdb_rev = attributes['_rev']
|
56
|
+
|
57
|
+
new(server_url, timestamp, salt, couchdb_rev)
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_json(*args)
|
61
|
+
result = {
|
62
|
+
'json_class' => self.class.name,
|
63
|
+
'chef_type' => 'nonce',
|
64
|
+
'server_url' => @server_url,
|
65
|
+
'timestamp' => @timestamp.to_i,
|
66
|
+
'salt' => @salt,
|
67
|
+
}
|
68
|
+
result['_rev'] = @couchdb_rev if @couchdb_rev
|
69
|
+
result.to_json(*args)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: matthewtodd-openid-store-couchdb-chef
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Todd
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-29 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: matthewtodd-shoe
|
17
|
+
type: :development
|
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: ruby-openid
|
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: chef
|
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
|
+
description:
|
46
|
+
email: matthew.todd@gmail.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.rdoc
|
53
|
+
files:
|
54
|
+
- Rakefile
|
55
|
+
- README.rdoc
|
56
|
+
- lib/openid
|
57
|
+
- lib/openid/store
|
58
|
+
- lib/openid/store/couchdb
|
59
|
+
- lib/openid/store/couchdb/association.rb
|
60
|
+
- lib/openid/store/couchdb/nonce.rb
|
61
|
+
- lib/openid/store/couchdb.rb
|
62
|
+
- lib/openid-store-couchdb.rb
|
63
|
+
has_rdoc: false
|
64
|
+
homepage:
|
65
|
+
licenses:
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --main
|
69
|
+
- README.rdoc
|
70
|
+
- --title
|
71
|
+
- openid-store-couchdb-chef-0.1.0
|
72
|
+
- --inline-source
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
version:
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
86
|
+
version:
|
87
|
+
requirements: []
|
88
|
+
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.3.5
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: A Chef-specific OpenID store for CouchDB.
|
94
|
+
test_files: []
|
95
|
+
|