gprov 0.0.3
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/LICENSE +14 -0
- data/README.markdown +7 -0
- data/Rakefile +5 -0
- data/lib/gprov.rb +4 -0
- data/lib/gprov/auth.rb +1 -0
- data/lib/gprov/auth/clientlogin.rb +65 -0
- data/lib/gprov/connection.rb +88 -0
- data/lib/gprov/error.rb +27 -0
- data/lib/gprov/provision.rb +9 -0
- data/lib/gprov/provision/customerid.rb +44 -0
- data/lib/gprov/provision/entrybase.rb +82 -0
- data/lib/gprov/provision/entrybase/classmethods.rb +52 -0
- data/lib/gprov/provision/entrybase/xmlattr.rb +92 -0
- data/lib/gprov/provision/feed.rb +44 -0
- data/lib/gprov/provision/group.rb +147 -0
- data/lib/gprov/provision/member.rb +48 -0
- data/lib/gprov/provision/orgmember.rb +84 -0
- data/lib/gprov/provision/orgunit.rb +89 -0
- data/lib/gprov/provision/owner.rb +46 -0
- data/lib/gprov/provision/user.rb +132 -0
- data/lib/gprov/version.rb +3 -0
- data/spec/gdata/auth/clientlogin_spec.rb +47 -0
- data/spec/gdata/connection_spec.rb +62 -0
- data/spec/gdata/provision/entrybase_spec.rb +39 -0
- data/spec/spec_helper.rb +10 -0
- metadata +118 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
# = gprov/provision/user.rb: implementation of the gprov provisioning userentry
|
2
|
+
#
|
3
|
+
# == Overview
|
4
|
+
#
|
5
|
+
# implementation of the gprov provisioning userentry
|
6
|
+
#
|
7
|
+
# == Authors
|
8
|
+
#
|
9
|
+
# Adrien Thebo
|
10
|
+
#
|
11
|
+
# == Copyright
|
12
|
+
#
|
13
|
+
# 2011 Puppet Labs
|
14
|
+
#
|
15
|
+
require 'gprov'
|
16
|
+
require 'gprov/provision/feed'
|
17
|
+
require 'gprov/provision/entrybase'
|
18
|
+
module GProv
|
19
|
+
module Provision
|
20
|
+
class User < GProv::Provision::EntryBase
|
21
|
+
|
22
|
+
# The :title attribute is only used after the account has been created
|
23
|
+
# TODO implement :none access for attributes. This should be hidden.
|
24
|
+
xmlattr :title, :type => :string, :xpath => "xmlns:title/text()"
|
25
|
+
|
26
|
+
xmlattr :user_name, :xpath => "apps:login/@userName"
|
27
|
+
xmlattr :suspended, :xpath => "apps:login/@suspended"
|
28
|
+
xmlattr :ip_whitelisted, :xpath => "apps:login/@ipWhitelisted"
|
29
|
+
xmlattr :admin, :xpath => "apps:login/@admin"
|
30
|
+
xmlattr :agreed_to_terms, :xpath => "apps:login/@agreedToTerms"
|
31
|
+
xmlattr :limit, :xpath => "apps:quota/@limit"
|
32
|
+
xmlattr :family_name, :xpath => "apps:name/@familyName"
|
33
|
+
xmlattr :given_name, :xpath => "apps:name/@givenName"
|
34
|
+
xmlattr :change_password_at_next_login, :xpath => "apps:login/@changePasswordAtNextLogin"
|
35
|
+
|
36
|
+
# Adds explicit ordering to attributes for cleaner output
|
37
|
+
def self.attribute_names
|
38
|
+
[
|
39
|
+
:user_name,
|
40
|
+
:given_name,
|
41
|
+
:family_name,
|
42
|
+
:admin,
|
43
|
+
:agreed_to_terms,
|
44
|
+
:change_password_at_next_login,
|
45
|
+
:suspended,
|
46
|
+
:ip_whitelisted,
|
47
|
+
:limit
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
# These attributes appear to never be sent from google but can be
|
52
|
+
# posted back
|
53
|
+
attr_accessor :password, :hash_function_name
|
54
|
+
|
55
|
+
# Retrieves all users within a domain
|
56
|
+
def self.all(connection)
|
57
|
+
feed = GProv::Provision::Feed.new(connection, "/:domain/user/2.0", "/xmlns:feed/xmlns:entry")
|
58
|
+
entries = feed.fetch
|
59
|
+
entries.map { |xml| new(:status => :clean, :connection => connection, :source => xml) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.get(connection, title, options={})
|
63
|
+
response = connection.get("/:domain/user/2.0/#{title}")
|
64
|
+
|
65
|
+
document = Nokogiri::XML(response.body)
|
66
|
+
xml = document.root
|
67
|
+
|
68
|
+
new(:status => :clean, :connection => connection, :source => xml)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Generate a nokogiri representation of this user
|
72
|
+
def to_nokogiri
|
73
|
+
base_document = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
74
|
+
xml.entry('xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
75
|
+
'xmlns:apps' => 'http://schemas.google.com/apps/2006' ) {
|
76
|
+
|
77
|
+
# Namespaces cannot be used until they are declared, so we need to
|
78
|
+
# retroactively declare the namespace of the parent
|
79
|
+
xml.parent.namespace = xml.parent.namespace_definitions.select {|ns| ns.prefix == "atom"}.first
|
80
|
+
xml.category("scheme" => "http://schemas.google.com/g/2005#kind",
|
81
|
+
"term" =>"http://schemas.google.com/apps/2006#user")
|
82
|
+
xml['apps'].login(login_attributes)
|
83
|
+
xml['apps'].quota("limit" => @limit) if @limit
|
84
|
+
xml['apps'].name("familyName" => @family_name, "givenName" => @given_name)
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
base_document
|
89
|
+
end
|
90
|
+
|
91
|
+
def create!
|
92
|
+
response = connection.post("/:domain/user/2.0", {:body => to_nokogiri.to_xml})
|
93
|
+
status = :clean
|
94
|
+
end
|
95
|
+
|
96
|
+
def update!
|
97
|
+
response = connection.put("/:domain/user/2.0/#{title}", {:body => to_nokogiri.to_xml})
|
98
|
+
status = :clean
|
99
|
+
end
|
100
|
+
|
101
|
+
def delete!
|
102
|
+
response = connection.delete("/:domain/user/2.0/#{title}")
|
103
|
+
status = :deleted
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
# Map object properties to xml tag attributes
|
109
|
+
def login_attributes
|
110
|
+
attrs = {}
|
111
|
+
|
112
|
+
attr_pairs = [
|
113
|
+
{"userName" => @user_name},
|
114
|
+
{"suspended" => @suspended},
|
115
|
+
{"ipWhitelisted" => @ip_whitelisted},
|
116
|
+
{"admin" => @admin},
|
117
|
+
{"changePasswordAtNextLogin" => @change_password_at_next_login},
|
118
|
+
{"agreedToTerms" => @agreed_to_terms},
|
119
|
+
{'password' => @password},
|
120
|
+
{'hashFunctionName' => @hash_function_name},
|
121
|
+
]
|
122
|
+
|
123
|
+
attr_pairs.each do |pair|
|
124
|
+
key = pair.keys.first
|
125
|
+
attrs.merge!(pair) unless pair[key].nil?
|
126
|
+
end
|
127
|
+
|
128
|
+
attrs
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GProv::Auth::ClientLogin do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@klass = GProv::Auth::ClientLogin
|
7
|
+
@instance = @klass.new('test', 'password', 'service')
|
8
|
+
@dummy_form = {:body => {
|
9
|
+
"accountType" => "HOSTED",
|
10
|
+
"Email" => "test",
|
11
|
+
"Passwd" => "password",
|
12
|
+
"service" => "service",
|
13
|
+
}}
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should use the google ClientLogin uri" do
|
17
|
+
GProv::Auth::ClientLogin.base_uri.should == "https://www.google.com/accounts/ClientLogin"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have a token method" do
|
21
|
+
@instance.respond_to?(:token).should == true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should post valid form data to the uri specified base_uri" do
|
25
|
+
stub_response = stub :response
|
26
|
+
stub_response.stubs(:code).returns 200
|
27
|
+
stub_response.stubs(:body).returns "Auth=dummy\n"
|
28
|
+
@klass.expects(:post).with('', @dummy_form).returns stub_response
|
29
|
+
@instance.token
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return nil if authorization failed" do
|
33
|
+
stub_response = stub :response
|
34
|
+
stub_response.stubs(:code).returns 403
|
35
|
+
@klass.expects(:post).with('', @dummy_form).returns stub_response
|
36
|
+
@instance.token.should be_nil
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return the token if authorization succeeded" do
|
40
|
+
stub_response = stub :response
|
41
|
+
stub_response.stubs(:code).returns 200
|
42
|
+
stub_response.stubs(:body).returns "Auth=dummy\n"
|
43
|
+
@klass.expects(:post).with('', @dummy_form).returns stub_response
|
44
|
+
@instance.token.should == "dummy"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GProv::Connection do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@klass = GProv::Connection
|
7
|
+
@instance = @klass.new("domain", "token")
|
8
|
+
|
9
|
+
@expected_options = {:headers => {
|
10
|
+
'Authorization' => "GoogleLogin auth=token",
|
11
|
+
'Content-Type' => 'application/atom+xml',
|
12
|
+
}}
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should use to google apps API url as the base uri" do
|
16
|
+
@klass.base_uri.should == "https://apps-apis.google.com/a/feeds"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have a domain accessor" do
|
20
|
+
@instance.respond_to?(:domain).should == true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should expose the default headers" do
|
24
|
+
@instance.default_headers.should == @expected_options
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
describe "http instance method" do
|
29
|
+
[:put, :get, :post, :delete].each do |verb|
|
30
|
+
describe %Q{"#{verb}"} do
|
31
|
+
before do
|
32
|
+
xml = %Q{<?xml version="1.0" encoding="UTF-8"?>\n<test xml="pointy"/>}
|
33
|
+
@stub_request = mock
|
34
|
+
@stub_request.stubs(:code).returns 200
|
35
|
+
@stub_request.stubs(:success?).returns true
|
36
|
+
@stub_request.stubs(:class).returns HTTParty::Response
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be an instance method" do
|
40
|
+
@instance.respond_to?(verb).should == true
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should be forwarded to the class" do
|
44
|
+
@klass.expects(verb).returns @stub_request
|
45
|
+
@instance.send(verb, '')
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should return the http response" do
|
49
|
+
@klass.expects(verb).returns @stub_request
|
50
|
+
output = @instance.send(verb, "/url")
|
51
|
+
output.class.should == HTTParty::Response
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should interpolate the :domain substring" do
|
55
|
+
@klass.expects(verb).with("/domain", @expected_options).returns @stub_request
|
56
|
+
@instance.send(verb, "/:domain")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class FakeEntry < GProv::Provision::EntryBase
|
4
|
+
|
5
|
+
xml_attr_accessor :test, :xpath => "/foo/bar/text()"
|
6
|
+
xml_attr_accessor :test_transform, :xpath => "/foo/bar/text()", :transform => lambda {|x| x.upcase}
|
7
|
+
end
|
8
|
+
|
9
|
+
describe GProv::Provision::EntryBase do
|
10
|
+
|
11
|
+
before do
|
12
|
+
@klass = GProv::Provision::EntryBase
|
13
|
+
@test_klass = FakeEntry
|
14
|
+
@instance = @test_klass.new
|
15
|
+
end
|
16
|
+
|
17
|
+
describe GProv::Provision::EntryBase::ClassMethods do
|
18
|
+
|
19
|
+
[:xml_attr_accessor, :xml_to_hash, :attributes].each do |method|
|
20
|
+
it "method #{method} should be a class method" do
|
21
|
+
FakeEntry.respond_to?(method).should be_true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "xml_attr_accessor should receive a symbol and hash of attributes" do
|
26
|
+
@test_klass.attributes[:test].should == {:xpath => "/foo/bar/text()"}
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "xml_to_hash" do
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
[:status, :connection].each do |method|
|
35
|
+
it "method #{method} should be an instance method" do
|
36
|
+
@instance.respond_to?(method).should be_true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gprov
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Adrien Thebo
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-02-02 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: httparty
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 27
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
- 8
|
32
|
+
version: "0.8"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: nokogiri
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 5
|
44
|
+
segments:
|
45
|
+
- 1
|
46
|
+
- 5
|
47
|
+
version: "1.5"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
description: Ruby bindings to the Google Provisioning API
|
51
|
+
email: adrien@puppetlabs.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- lib/gprov/auth/clientlogin.rb
|
60
|
+
- lib/gprov/auth.rb
|
61
|
+
- lib/gprov/connection.rb
|
62
|
+
- lib/gprov/error.rb
|
63
|
+
- lib/gprov/provision/customerid.rb
|
64
|
+
- lib/gprov/provision/entrybase/classmethods.rb
|
65
|
+
- lib/gprov/provision/entrybase/xmlattr.rb
|
66
|
+
- lib/gprov/provision/entrybase.rb
|
67
|
+
- lib/gprov/provision/feed.rb
|
68
|
+
- lib/gprov/provision/group.rb
|
69
|
+
- lib/gprov/provision/member.rb
|
70
|
+
- lib/gprov/provision/orgmember.rb
|
71
|
+
- lib/gprov/provision/orgunit.rb
|
72
|
+
- lib/gprov/provision/owner.rb
|
73
|
+
- lib/gprov/provision/user.rb
|
74
|
+
- lib/gprov/provision.rb
|
75
|
+
- lib/gprov/version.rb
|
76
|
+
- lib/gprov.rb
|
77
|
+
- spec/gdata/auth/clientlogin_spec.rb
|
78
|
+
- spec/gdata/connection_spec.rb
|
79
|
+
- spec/gdata/provision/entrybase_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- LICENSE
|
82
|
+
- Rakefile
|
83
|
+
- README.markdown
|
84
|
+
homepage: http://github.com/adrienthebo/ruby-gprov
|
85
|
+
licenses: []
|
86
|
+
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
hash: 3
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
requirements: []
|
111
|
+
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.8.10
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Ruby bindings to the Google Provisioning API
|
117
|
+
test_files: []
|
118
|
+
|