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,44 @@
|
|
1
|
+
# Generic representation of the various types of feeds available from the
|
2
|
+
# provisioning api
|
3
|
+
require 'gprov'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
module GProv
|
7
|
+
module Provision
|
8
|
+
class Feed
|
9
|
+
|
10
|
+
attr_reader :results
|
11
|
+
def initialize(connection, path, xpath)
|
12
|
+
@connection = connection
|
13
|
+
@url = path
|
14
|
+
@xpath = xpath
|
15
|
+
|
16
|
+
@results = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch
|
20
|
+
retrieve_page
|
21
|
+
@results
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def retrieve_page
|
27
|
+
response = @connection.get(@url)
|
28
|
+
|
29
|
+
if response.code == 200
|
30
|
+
document = Nokogiri::XML(response.body)
|
31
|
+
entries = document.xpath(@xpath)
|
32
|
+
|
33
|
+
@results.concat(entries.to_a)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def retrieve_all
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# = gprov/provision/group.rb: implementation of the gprov provisioning groupentry
|
2
|
+
#
|
3
|
+
# == Overview
|
4
|
+
#
|
5
|
+
# implementation of the gprov provisioning groupentry
|
6
|
+
#
|
7
|
+
# == Authors
|
8
|
+
#
|
9
|
+
# Adrien Thebo
|
10
|
+
#
|
11
|
+
# == Copyright
|
12
|
+
#
|
13
|
+
# 2011 Puppet Labs
|
14
|
+
#
|
15
|
+
require 'gprov'
|
16
|
+
require 'gprov/provision/entrybase'
|
17
|
+
require 'gprov/provision/member'
|
18
|
+
require 'gprov/provision/owner'
|
19
|
+
module GProv
|
20
|
+
module Provision
|
21
|
+
class Group < GProv::Provision::EntryBase
|
22
|
+
|
23
|
+
# TODO copy group_id on instantiation so that groups can change
|
24
|
+
# their IDs without exploding
|
25
|
+
xmlattr :group_id, :xpath => %Q{apps:property[@name = "groupId"]/@value}
|
26
|
+
xmlattr :group_name, :xpath => %Q{apps:property[@name = "groupName"]/@value}
|
27
|
+
xmlattr :email_permission, :xpath => %Q{apps:property[@name = "emailPermission"]/@value}
|
28
|
+
xmlattr :permission_preset, :xpath => %Q{apps:property[@name = "permissionPreset"]/@value}
|
29
|
+
xmlattr :description, :xpath => %Q{apps:property[@name = "description"]/@value}
|
30
|
+
|
31
|
+
# Retrieves all users within a domain
|
32
|
+
def self.all(connection, options={})
|
33
|
+
|
34
|
+
# TODO Fail if unrecognized options passed
|
35
|
+
url = "/group/2.0/:domain"
|
36
|
+
if member = options[:member]
|
37
|
+
url << "/?member=#{member}"
|
38
|
+
|
39
|
+
if direct_only = options[:direct_only]
|
40
|
+
url << "&directOnly=#{direct_only}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
feed = GProv::Provision::Feed.new(connection, url, "/xmlns:feed/xmlns:entry")
|
45
|
+
entries = feed.fetch
|
46
|
+
entries.map { |xml| new(:status => :clean, :connection => connection, :source => xml) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.get(connection, group_id)
|
50
|
+
response = connection.get("/group/2.0/:domain/#{group_id}")
|
51
|
+
document = Nokogiri::XML(response.body)
|
52
|
+
xml = document.root
|
53
|
+
|
54
|
+
new(:status => :clean, :connection => connection, :source => xml)
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_nokogiri
|
58
|
+
base_document = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
59
|
+
xml.entry('xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
60
|
+
'xmlns:apps' => 'http://schemas.google.com/apps/2006',
|
61
|
+
'xmlns:gd' => "http://schemas.google.com/g/2005" ) {
|
62
|
+
|
63
|
+
# Namespaces cannot be used until they are declared, so we need to
|
64
|
+
# retroactively declare the namespace of the parent
|
65
|
+
xml.parent.namespace = xml.parent.namespace_definitions.select {|ns| ns.prefix == "atom"}.first
|
66
|
+
xml.category("scheme" => "http://schemas.google.com/g/2005#kind",
|
67
|
+
"term" =>"http://schemas.google.com/apps/2006#user")
|
68
|
+
|
69
|
+
xml['apps'].property("name" => "groupId", "value" => @group_id)
|
70
|
+
xml['apps'].property("name" => "groupName", "value" => @group_name)
|
71
|
+
xml['apps'].property("name" => "emailPermission", "value" => @email_permission)
|
72
|
+
xml['apps'].property("name" => "description", "value" => @description)
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
base_document
|
77
|
+
end
|
78
|
+
|
79
|
+
def create!
|
80
|
+
response = connection.post("/group/2.0/:domain", {:body => to_nokogiri.to_xml})
|
81
|
+
status = :clean
|
82
|
+
end
|
83
|
+
|
84
|
+
def update!
|
85
|
+
response = connection.put("/group/2.0/:domain", {:body => to_nokogiri.to_xml})
|
86
|
+
status = :clean
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete!
|
90
|
+
response = connection.put("/group/2.0/:domain/#{group_id}")
|
91
|
+
status = :deleted
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_member(membername)
|
95
|
+
member = GProv::Provision::Member.new(
|
96
|
+
:connection => @connection,
|
97
|
+
:source => {
|
98
|
+
:group_id => @group_id,
|
99
|
+
:member_id => membername,
|
100
|
+
}
|
101
|
+
)
|
102
|
+
member.create!
|
103
|
+
end
|
104
|
+
|
105
|
+
def del_member(membername)
|
106
|
+
member = GProv::Provision::Member.new(
|
107
|
+
:connection => @connection,
|
108
|
+
:source => {
|
109
|
+
:group_id => @group_id,
|
110
|
+
:member_id => membername,
|
111
|
+
}
|
112
|
+
)
|
113
|
+
member.delete!
|
114
|
+
end
|
115
|
+
|
116
|
+
def list_members
|
117
|
+
GProv::Provision::Member.all(@connection, @group_id)
|
118
|
+
end
|
119
|
+
|
120
|
+
def add_owner(ownername)
|
121
|
+
owner = GProv::Provision::Owner.new(
|
122
|
+
:connection => @connection,
|
123
|
+
:source => {
|
124
|
+
:group_id => @group_id,
|
125
|
+
:email => ownername,
|
126
|
+
}
|
127
|
+
)
|
128
|
+
owner.create!
|
129
|
+
end
|
130
|
+
|
131
|
+
def del_owner(ownername)
|
132
|
+
owner = GProv::Provision::Owner.new(
|
133
|
+
:connection => @connection,
|
134
|
+
:source => {
|
135
|
+
:group_id => @group_id,
|
136
|
+
:email => ownername,
|
137
|
+
}
|
138
|
+
)
|
139
|
+
owner.delete!
|
140
|
+
end
|
141
|
+
|
142
|
+
def list_owners
|
143
|
+
GProv::Provision::Owner.all(@connection, @group_id)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Representation of group members
|
2
|
+
require 'gprov'
|
3
|
+
require 'gprov/provision/entrybase'
|
4
|
+
|
5
|
+
module GProv
|
6
|
+
module Provision
|
7
|
+
class Member < GProv::Provision::EntryBase
|
8
|
+
|
9
|
+
xmlattr :member_id, :xpath => %Q{apps:property[@name = "memberId"]/@value}
|
10
|
+
xmlattr :member_type, :xpath => %Q{apps:property[@name = "memberType"]/@value}
|
11
|
+
xmlattr :direct_member, :xpath => %Q{apps:property[@name = "directMember"]/@value}
|
12
|
+
attr_accessor :group_id
|
13
|
+
|
14
|
+
def self.all(connection, group_id)
|
15
|
+
feed = GProv::Provision::Feed.new(connection, "/group/2.0/:domain/#{group_id}/member", "/xmlns:feed/xmlns:entry")
|
16
|
+
entries = feed.fetch
|
17
|
+
entries.map { |xml| new(:status => :clean, :connection => connection, :source => xml) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_nokogiri
|
21
|
+
base_document = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
22
|
+
xml.entry('xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
23
|
+
'xmlns:apps' => 'http://schemas.google.com/apps/2006',
|
24
|
+
'xmlns:gd' => "http://schemas.google.com/g/2005" ) {
|
25
|
+
|
26
|
+
# Namespaces cannot be used until they are declared, so we need to
|
27
|
+
# retroactively declare the namespace of the parent
|
28
|
+
xml.parent.namespace = xml.parent.namespace_definitions.select {|ns| ns.prefix == "atom"}.first
|
29
|
+
|
30
|
+
xml['apps'].property("name" => "memberId", "value" => @member_id)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
base_document
|
35
|
+
end
|
36
|
+
|
37
|
+
def create!
|
38
|
+
response = connection.post("/group/2.0/:domain/#{@group_id}/member", {:body => to_nokogiri.to_xml})
|
39
|
+
status = :clean
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete!
|
43
|
+
response = connection.delete("/group/2.0/:domain/#{@group_id}/member/#{@member_id}")
|
44
|
+
status = :clean
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# = gprov/provision/orgmember.rb
|
2
|
+
#
|
3
|
+
# == Overview
|
4
|
+
#
|
5
|
+
# Representation of the members of organizational units
|
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 OrgMember < GProv::Provision::EntryBase
|
21
|
+
|
22
|
+
# This attribute will only be received and never sent
|
23
|
+
xmlattr :org_user_email, :xpath => %Q{apps:property[@name = "orgUserEmail"]/@value}
|
24
|
+
xmlattr :org_unit_path, :xpath => %Q{apps:property[@name = "orgUnitPath"]/@value}
|
25
|
+
|
26
|
+
# Retrieve all organization users in the domain.
|
27
|
+
def self.all(connection, options = {:target => :all})
|
28
|
+
id = GProv::Provision::CustomerID.get(connection)
|
29
|
+
|
30
|
+
case options[:target]
|
31
|
+
when :orgunit
|
32
|
+
# XXX validation
|
33
|
+
url = "/orguser/2.0/#{id.customer_id}?get=children&orgUnitPath=#{options[:orgunit]}"
|
34
|
+
when :all
|
35
|
+
url = "/orguser/2.0/#{id.customer_id}?get=all"
|
36
|
+
end
|
37
|
+
|
38
|
+
feed = GProv::Provision::Feed.new(connection, url, "/xmlns:feed/xmlns:entry")
|
39
|
+
entries = feed.fetch
|
40
|
+
entries.map { |xml| new(:status => :clean, :connection => connection, :source => xml) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.get(connection, email)
|
44
|
+
id = GProv::Provision::CustomerID.get(connection)
|
45
|
+
response = connection.get("/orguser/2.0/#{id.customer_id}/#{email}")
|
46
|
+
|
47
|
+
document = Nokogiri::XML(response.body)
|
48
|
+
xml = document.root
|
49
|
+
|
50
|
+
new(:status => :clean, :connection => connection, :source => xml)
|
51
|
+
end
|
52
|
+
|
53
|
+
# This attribute will only be sent and never received
|
54
|
+
def initialize(opts={})
|
55
|
+
super
|
56
|
+
# Generate this variable in the case that the org_unit_path is updated
|
57
|
+
@old_org_unit_path = @org_unit_path
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_nokogiri
|
61
|
+
base_document = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
62
|
+
xml.entry('xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
63
|
+
'xmlns:apps' => 'http://schemas.google.com/apps/2006',
|
64
|
+
'xmlns:gd' => "http://schemas.google.com/g/2005" ) {
|
65
|
+
|
66
|
+
# Namespaces cannot be used until they are declared, so we need to
|
67
|
+
# retroactively declare the namespace of the parent
|
68
|
+
xml.parent.namespace = xml.parent.namespace_definitions.select {|ns| ns.prefix == "atom"}.first
|
69
|
+
|
70
|
+
xml['apps'].property("name" => "orgUnitPath", "value" => @org_unit_path)
|
71
|
+
xml['apps'].property("name" => "oldOrgUnitPath", "value" => @old_org_unit_path)
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def update!
|
77
|
+
id = GProv::Provision::CustomerID.get(connection)
|
78
|
+
response = connection.put("/orguser/2.0/#{id.customer_id}/#{@org_user_email}", {:body => to_nokogiri.to_xml})
|
79
|
+
status = :clean
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# = gprov/provision/orgunit.rb
|
2
|
+
#
|
3
|
+
# == Overview
|
4
|
+
#
|
5
|
+
# implementation of the gprov organizational unit
|
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
|
+
require 'gprov/provision/customerid'
|
19
|
+
require 'gprov/provision/orgmember'
|
20
|
+
module GProv
|
21
|
+
module Provision
|
22
|
+
class OrgUnit < GProv::Provision::EntryBase
|
23
|
+
|
24
|
+
xmlattr :name, :xpath => %Q{apps:property[@name = "name"]/@value}
|
25
|
+
xmlattr :description, :xpath => %Q{apps:property[@name = "description"]/@value}
|
26
|
+
xmlattr :org_unit_path, :xpath => %Q{apps:property[@name = "orgUnitPath"]/@value}
|
27
|
+
xmlattr :parent_org_unit_path, :xpath => %Q{apps:property[@name = "parentOrgUnitPath"]/@value}
|
28
|
+
xmlattr :block_inheritance, :xpath => %Q{apps:property[@name = "blockInheritance"]/@value}
|
29
|
+
|
30
|
+
def self.all(connection)
|
31
|
+
id = GProv::Provision::CustomerID.get(connection)
|
32
|
+
feed = GProv::Provision::Feed.new(connection, "/orgunit/2.0/#{id.customer_id}?get=all", "/xmlns:feed/xmlns:entry")
|
33
|
+
entries = feed.fetch
|
34
|
+
entries.map { |xml| new(:status => :clean, :connection => connection, :source => xml) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.get(connection, org_path)
|
38
|
+
id = GProv::Provision::CustomerID.get(connection)
|
39
|
+
response = connection.get("/orgunit/2.0/#{id.customer_id}/#{org_path}")
|
40
|
+
document = Nokogiri::XML(response.body)
|
41
|
+
xml = document.root
|
42
|
+
|
43
|
+
new(:status => :clean, :connection => connection, :source => xml)
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_nokogiri
|
47
|
+
base_document = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
48
|
+
xml.entry('xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
49
|
+
'xmlns:apps' => 'http://schemas.google.com/apps/2006',
|
50
|
+
'xmlns:gd' => "http://schemas.google.com/g/2005" ) {
|
51
|
+
|
52
|
+
# Namespaces cannot be used until they are declared, so we need to
|
53
|
+
# retroactively declare the namespace of the parent
|
54
|
+
xml.parent.namespace = xml.parent.namespace_definitions.select {|ns| ns.prefix == "atom"}.first
|
55
|
+
|
56
|
+
xml['apps'].property("name" => "name", "value" => @name)
|
57
|
+
xml['apps'].property("name" => "description", "value" => @description)
|
58
|
+
xml['apps'].property("name" => "parentOrgUnitPath", "value" => @parent_org_unit_path)
|
59
|
+
xml['apps'].property("name" => "blockInheritance", "value" => @block_inheritance)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create!
|
65
|
+
# xxx cache this?
|
66
|
+
id = GProv::Provision::CustomerID.get(connection)
|
67
|
+
response = connection.post("/orgunit/2.0/#{id.customer_id}")
|
68
|
+
status = :clean
|
69
|
+
end
|
70
|
+
|
71
|
+
def update!
|
72
|
+
# xxx cache this?
|
73
|
+
id = GProv::Provision::Customerid.get(connection)
|
74
|
+
response = connection.put("/orgunit/2.0/#{id.customer_id}/#{@org_unit_path}")
|
75
|
+
status = :clean
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete!
|
79
|
+
id = GProv::Provision::Customerid.get(connection)
|
80
|
+
response = connection.delete("/orgunit/2.0/#{id.customer_id}/#{@org_unit_path}")
|
81
|
+
status = :deleted
|
82
|
+
end
|
83
|
+
|
84
|
+
def list_members
|
85
|
+
GProv::Provision::OrgMember.all(connection, :target => :orgunit, :orgunit => @org_unit_path)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Representation of group owners
|
2
|
+
require 'gprov'
|
3
|
+
require 'gprov/provision/entrybase'
|
4
|
+
|
5
|
+
module GProv
|
6
|
+
module Provision
|
7
|
+
class Owner < GProv::Provision::EntryBase
|
8
|
+
|
9
|
+
xmlattr :email, :xpath => %Q{apps:property[@name = "email"]/@value}
|
10
|
+
attr_accessor :group_id
|
11
|
+
|
12
|
+
def self.all(connection, group_id)
|
13
|
+
feed = GProv::Provision::Feed.new(connection, "/group/2.0/:domain/#{group_id}/owner", "/xmlns:feed/xmlns:entry")
|
14
|
+
entries = feed.fetch
|
15
|
+
entries.map { |xml| new(:status => :clean, :connection => connection, :source => xml) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_nokogiri
|
19
|
+
base_document = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
20
|
+
xml.entry('xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
21
|
+
'xmlns:apps' => 'http://schemas.google.com/apps/2006',
|
22
|
+
'xmlns:gd' => "http://schemas.google.com/g/2005" ) {
|
23
|
+
|
24
|
+
# Namespaces cannot be used until they are declared, so we need to
|
25
|
+
# retroactively declare the namespace of the parent
|
26
|
+
xml.parent.namespace = xml.parent.namespace_definitions.select {|ns| ns.prefix == "atom"}.first
|
27
|
+
|
28
|
+
xml['apps'].property("name" => "email", "value" => @email)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
base_document
|
33
|
+
end
|
34
|
+
|
35
|
+
def create!
|
36
|
+
response = connection.post("/group/2.0/:domain/#{@group_id}/owner", {:body => to_nokogiri.to_xml})
|
37
|
+
status = :clean
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete!
|
41
|
+
response = connection.delete("/group/2.0/:domain/#{@group_id}/owner/#{@email}")
|
42
|
+
status = :clean
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|