chef-server-slice 0.7.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +135 -0
  3. data/app/controllers/application.rb +228 -0
  4. data/app/controllers/cookbook_attributes.rb +59 -0
  5. data/app/controllers/cookbook_definitions.rb +60 -0
  6. data/app/controllers/cookbook_files.rb +94 -0
  7. data/app/controllers/cookbook_libraries.rb +60 -0
  8. data/app/controllers/cookbook_recipes.rb +59 -0
  9. data/app/controllers/cookbook_templates.rb +80 -0
  10. data/app/controllers/cookbooks.rb +63 -0
  11. data/app/controllers/exceptions.rb +33 -0
  12. data/app/controllers/main.rb +7 -0
  13. data/app/controllers/nodes.rb +144 -0
  14. data/app/controllers/openid_consumer.rb +133 -0
  15. data/app/controllers/openid_register.rb +113 -0
  16. data/app/controllers/openid_server.rb +252 -0
  17. data/app/controllers/roles.rb +138 -0
  18. data/app/controllers/search.rb +58 -0
  19. data/app/controllers/search_entries.rb +73 -0
  20. data/app/controllers/status.rb +34 -0
  21. data/app/helpers/application_helper.rb +144 -0
  22. data/app/helpers/cookbook_attributes_helper.rb +7 -0
  23. data/app/helpers/cookbook_definitions_helper.rb +8 -0
  24. data/app/helpers/cookbook_files_helper.rb +8 -0
  25. data/app/helpers/cookbook_libraries_helper.rb +7 -0
  26. data/app/helpers/cookbook_recipes_helper.rb +8 -0
  27. data/app/helpers/cookbook_templates_helper.rb +8 -0
  28. data/app/helpers/cookbooks_helper.rb +31 -0
  29. data/app/helpers/exceptions_helper.rb +6 -0
  30. data/app/helpers/global_helpers.rb +39 -0
  31. data/app/helpers/nodes_helper.rb +33 -0
  32. data/app/helpers/openid_consumer_helper.rb +8 -0
  33. data/app/helpers/openid_register_helper.rb +8 -0
  34. data/app/helpers/openid_server_helper.rb +6 -0
  35. data/app/helpers/openid_server_helpers.rb +29 -0
  36. data/app/helpers/roles_helper.rb +5 -0
  37. data/app/helpers/search_entries_helper.rb +8 -0
  38. data/app/helpers/search_helper.rb +38 -0
  39. data/app/helpers/status_helper.rb +26 -0
  40. data/app/views/cookbook_templates/index.html.haml +7 -0
  41. data/app/views/cookbooks/index.html.haml +10 -0
  42. data/app/views/cookbooks/show.html.haml +40 -0
  43. data/app/views/exceptions/bad_request.json.erb +1 -0
  44. data/app/views/exceptions/internal_server_error.html.erb +216 -0
  45. data/app/views/exceptions/not_acceptable.html.erb +63 -0
  46. data/app/views/exceptions/not_found.html.erb +47 -0
  47. data/app/views/exceptions/standard_error.html.erb +217 -0
  48. data/app/views/layout/chef_server_slice.html.haml +53 -0
  49. data/app/views/layout/login.html.haml +37 -0
  50. data/app/views/main/index.html.erb +1 -0
  51. data/app/views/nodes/_action.html.haml +13 -0
  52. data/app/views/nodes/_form.html.haml +56 -0
  53. data/app/views/nodes/_navigation.html.haml +9 -0
  54. data/app/views/nodes/_resource.html.haml +22 -0
  55. data/app/views/nodes/edit.html.haml +7 -0
  56. data/app/views/nodes/index.html.haml +25 -0
  57. data/app/views/nodes/new.html.haml +6 -0
  58. data/app/views/nodes/show.html.haml +60 -0
  59. data/app/views/openid_consumer/index.html.haml +23 -0
  60. data/app/views/openid_consumer/start.html.haml +4 -0
  61. data/app/views/openid_login/index.html.haml +5 -0
  62. data/app/views/openid_register/index.html.haml +19 -0
  63. data/app/views/openid_register/show.html.haml +7 -0
  64. data/app/views/openid_server/decide.html.haml +27 -0
  65. data/app/views/roles/_form.html.haml +48 -0
  66. data/app/views/roles/_navigation.html.haml +9 -0
  67. data/app/views/roles/edit.html.haml +6 -0
  68. data/app/views/roles/index.html.haml +22 -0
  69. data/app/views/roles/new.html.haml +6 -0
  70. data/app/views/roles/show.html.haml +29 -0
  71. data/app/views/search/_search_form.html.haml +6 -0
  72. data/app/views/search/index.html.haml +9 -0
  73. data/app/views/search/show.html.haml +14 -0
  74. data/app/views/search_entries/index.html.haml +8 -0
  75. data/app/views/search_entries/show.html.haml +7 -0
  76. data/app/views/status/index.html.haml +88 -0
  77. data/config/init.rb +48 -0
  78. data/config/router.rb +6 -0
  79. data/lib/chef-server-slice.rb +150 -0
  80. data/lib/chef-server-slice/merbtasks.rb +103 -0
  81. data/lib/chef-server-slice/slicetasks.rb +20 -0
  82. data/lib/chef-server-slice/spectasks.rb +53 -0
  83. data/public/facebox/README.txt +4 -0
  84. data/public/facebox/b.png +0 -0
  85. data/public/facebox/bl.png +0 -0
  86. data/public/facebox/br.png +0 -0
  87. data/public/facebox/closelabel.gif +0 -0
  88. data/public/facebox/facebox.css +95 -0
  89. data/public/facebox/facebox.js +319 -0
  90. data/public/facebox/loading.gif +0 -0
  91. data/public/facebox/tl.png +0 -0
  92. data/public/facebox/tr.png +0 -0
  93. data/public/images/avatar.png +0 -0
  94. data/public/images/black_big.png +0 -0
  95. data/public/images/indicator.gif +0 -0
  96. data/public/images/merb.jpg +0 -0
  97. data/public/images/toggle-collapse-dark.png +0 -0
  98. data/public/images/toggle-collapse-light.png +0 -0
  99. data/public/images/toggle-collapse.gif +0 -0
  100. data/public/images/toggle-expand-dark.png +0 -0
  101. data/public/images/toggle-expand-light.png +0 -0
  102. data/public/images/toggle-expand.gif +0 -0
  103. data/public/images/treeBuilderImages/Thumbs.db +0 -0
  104. data/public/images/treeBuilderImages/doc.gif +0 -0
  105. data/public/images/treeBuilderImages/docNode.gif +0 -0
  106. data/public/images/treeBuilderImages/docNodeLast.gif +0 -0
  107. data/public/images/treeBuilderImages/docNodeLastFirst.gif +0 -0
  108. data/public/images/treeBuilderImages/folder.gif +0 -0
  109. data/public/images/treeBuilderImages/folderNode.gif +0 -0
  110. data/public/images/treeBuilderImages/folderNodeFirst.gif +0 -0
  111. data/public/images/treeBuilderImages/folderNodeLast.gif +0 -0
  112. data/public/images/treeBuilderImages/folderNodeLastFirst.gif +0 -0
  113. data/public/images/treeBuilderImages/folderNodeOpen.gif +0 -0
  114. data/public/images/treeBuilderImages/folderNodeOpenFirst.gif +0 -0
  115. data/public/images/treeBuilderImages/folderNodeOpenLast.gif +0 -0
  116. data/public/images/treeBuilderImages/folderNodeOpenLastFirst.gif +0 -0
  117. data/public/images/treeBuilderImages/folderOpen.gif +0 -0
  118. data/public/images/treeBuilderImages/vertLine.gif +0 -0
  119. data/public/javascripts/JSONeditor.js +1171 -0
  120. data/public/javascripts/chef.js +126 -0
  121. data/public/javascripts/jquery-1.3.2.min.js +19 -0
  122. data/public/javascripts/jquery-ui-1.7.1.custom.min.js +65 -0
  123. data/public/javascripts/jquery.editinline.js +108 -0
  124. data/public/javascripts/jquery.jeditable.mini.js +30 -0
  125. data/public/javascripts/jquery.livequery.js +250 -0
  126. data/public/javascripts/jquery.localscroll.js +104 -0
  127. data/public/javascripts/jquery.scrollTo.js +150 -0
  128. data/public/javascripts/jquery.tools.min.js +17 -0
  129. data/public/javascripts/jquery.treeTable.min.js +165 -0
  130. data/public/stylesheets/base.css +336 -0
  131. data/public/stylesheets/chef.css +157 -0
  132. data/public/stylesheets/images/ui-bg_diagonals-small_0_aaaaaa_40x40.png +0 -0
  133. data/public/stylesheets/images/ui-bg_diagonals-thick_15_444444_40x40.png +0 -0
  134. data/public/stylesheets/images/ui-bg_glass_100_f0f0f0_1x400.png +0 -0
  135. data/public/stylesheets/images/ui-bg_glass_50_99c2ff_1x400.png +0 -0
  136. data/public/stylesheets/images/ui-bg_glass_55_fbf5d0_1x400.png +0 -0
  137. data/public/stylesheets/images/ui-bg_glass_80_e6e6e6_1x400.png +0 -0
  138. data/public/stylesheets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  139. data/public/stylesheets/images/ui-bg_highlight-hard_100_f9f9f9_1x100.png +0 -0
  140. data/public/stylesheets/images/ui-bg_highlight-soft_100_e7eef3_1x100.png +0 -0
  141. data/public/stylesheets/images/ui-icons_222222_256x240.png +0 -0
  142. data/public/stylesheets/images/ui-icons_2694e8_256x240.png +0 -0
  143. data/public/stylesheets/images/ui-icons_2e83ff_256x240.png +0 -0
  144. data/public/stylesheets/images/ui-icons_72a7cf_256x240.png +0 -0
  145. data/public/stylesheets/images/ui-icons_888888_256x240.png +0 -0
  146. data/public/stylesheets/images/ui-icons_cd0a0a_256x240.png +0 -0
  147. data/public/stylesheets/images/ui-icons_ffffff_256x240.png +0 -0
  148. data/public/stylesheets/jquery-ui-1.7.1.custom.css +404 -0
  149. data/public/stylesheets/jquery.treeTable.css +43 -0
  150. data/public/stylesheets/themes/bec-green/style.css +290 -0
  151. data/public/stylesheets/themes/bec/style.css +301 -0
  152. data/public/stylesheets/themes/blue/style.css +280 -0
  153. data/public/stylesheets/themes/default/style.css +267 -0
  154. data/public/stylesheets/themes/djime-cerulean/style.css +298 -0
  155. data/public/stylesheets/themes/kathleene/style.css +272 -0
  156. data/public/stylesheets/themes/orange/style.css +263 -0
  157. data/public/stylesheets/themes/reidb-greenish/style.css +301 -0
  158. metadata +341 -0
@@ -0,0 +1,33 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ class ChefServerSlice::Exceptions < ChefServerSlice::Application
21
+
22
+ provides :html, :json
23
+
24
+ def standard_error
25
+ Merb.logger.warn(request.content_type)
26
+ if request.accept =~ /application\/json/
27
+ display({ "error" => request.exceptions })
28
+ else
29
+ raise request.exceptions.first
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,7 @@
1
+ class ChefServerSlice::Main < ChefServerSlice::Application
2
+
3
+ def index
4
+ render
5
+ end
6
+
7
+ end
@@ -0,0 +1,144 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef' / 'node'
21
+
22
+ class ChefServerSlice::Nodes < ChefServerSlice::Application
23
+
24
+ provides :html, :json
25
+
26
+ before :fix_up_node_id
27
+ before :login_required
28
+ before :authorized_node, :only => [ :update, :destroy ]
29
+
30
+ def index
31
+ @node_list = Chef::Node.list
32
+ display(@node_list.collect { |n| absolute_slice_url(:node, escape_node_id(n)) })
33
+ end
34
+
35
+ def show
36
+ begin
37
+ @node = Chef::Node.load(params[:id])
38
+ rescue Net::HTTPServerException => e
39
+ raise NotFound, "Cannot load node #{params[:id]}"
40
+ end
41
+ # TODO - might as well expand the run list here, too, rather than take multiple round trips.
42
+ recipes, defaults, overrides = @node.run_list.expand("couchdb")
43
+ @node.default = defaults
44
+ @node.override = overrides
45
+ display @node
46
+ end
47
+
48
+ def new
49
+ @node = Chef::Node.new
50
+ @available_recipes = get_available_recipes
51
+ @available_roles = Chef::Role.list.sort
52
+ @run_list = @node.run_list
53
+ render
54
+ end
55
+
56
+ def edit
57
+ begin
58
+ @node = Chef::Node.load(params[:id])
59
+ rescue Net::HTTPServerException => e
60
+ raise NotFound, "Cannot load node #{params[:id]}"
61
+ end
62
+ @available_recipes = get_available_recipes
63
+ @available_roles = Chef::Role.list.sort
64
+ @run_list = @node.run_list
65
+ render
66
+ end
67
+
68
+ def create
69
+ if params.has_key?("inflated_object")
70
+ @node = params["inflated_object"]
71
+ exists = true
72
+ begin
73
+ Chef::Node.load(@node.name)
74
+ rescue Net::HTTPServerException
75
+ exists = false
76
+ end
77
+ raise Forbidden, "Node already exists" if exists
78
+ self.status = 201
79
+ @node.save
80
+ display({ :uri => absolute_slice_url(:node, escape_node_id(@node.name)) })
81
+ else
82
+ begin
83
+ @node = Chef::Node.new
84
+ @node.name params[:name]
85
+ @node.attribute = JSON.parse(params[:attributes])
86
+ @node.run_list params[:for_node]
87
+ @node.save
88
+ redirect(slice_url(:nodes), :message => { :notice => "Created Node #{@node.name}" })
89
+ rescue
90
+ @node.attribute = JSON.parse(params[:attributes])
91
+ @available_recipes = get_available_recipes
92
+ @available_roles = Chef::Role.list.sort
93
+ @run_list = params[:for_node]
94
+ @_message = { :error => $! }
95
+ render :new
96
+ end
97
+ end
98
+ end
99
+
100
+ def update
101
+ begin
102
+ @node = Chef::Node.load(params[:id])
103
+ rescue Net::HTTPServerException => e
104
+ raise NotFound, "Cannot load node #{params[:id]}"
105
+ end
106
+
107
+ if params.has_key?("inflated_object")
108
+ updated = params['inflated_object']
109
+ @node.run_list.reset(updated.run_list)
110
+ @node.attribute = updated.attribute
111
+ @node.save
112
+ display(@node)
113
+ else
114
+ begin
115
+ @node.run_list.reset(params[:for_node] ? params[:for_node] : [])
116
+ @node.attribute = JSON.parse(params[:attributes])
117
+ @node.save
118
+ @_message = { :notice => "Updated Node" }
119
+ render :show
120
+ rescue
121
+ @available_recipes = get_available_recipes
122
+ @available_roles = Chef::Role.list.sort
123
+ @run_list = Chef::RunList.new
124
+ @run_list.reset(params[:for_node])
125
+ render :edit
126
+ end
127
+ end
128
+ end
129
+
130
+ def destroy
131
+ begin
132
+ @node = Chef::Node.load(params[:id])
133
+ rescue Net::HTTPServerException => e
134
+ raise NotFound, "Cannot load node #{params[:id]}"
135
+ end
136
+ @node.destroy
137
+ if request.accept == 'application/json'
138
+ display @node
139
+ else
140
+ redirect(absolute_slice_url(:nodes), {:message => { :notice => "Node #{params[:id]} deleted successfully" }, :permanent => true})
141
+ end
142
+ end
143
+
144
+ end
@@ -0,0 +1,133 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'pathname'
21
+ require 'openid'
22
+ require (Chef::Config[:openid_cstore_couchdb] ? 'openid-store-couchdb' : 'openid/store/filesystem')
23
+
24
+ class ChefServerSlice::OpenidConsumer < ChefServerSlice::Application
25
+
26
+ provides :html, :json
27
+
28
+ def index
29
+ if request.xhr?
30
+ render :layout => false
31
+ else
32
+ render :layout => 'login'
33
+ end
34
+ end
35
+
36
+ def start
37
+ oid = params[:openid_identifier]
38
+ begin
39
+ oidreq = consumer.begin(oid)
40
+ rescue OpenID::OpenIDError => e
41
+ raise BadRequest, "Discovery failed for #{oid}: #{e}"
42
+ end
43
+
44
+ return_to = absolute_slice_url(:openid_consumer_complete)
45
+ realm = absolute_slice_url(:openid_consumer)
46
+
47
+ if oidreq.send_redirect?(realm, return_to, params[:immediate])
48
+ return redirect(oidreq.redirect_url(realm, return_to, params[:immediate]))
49
+ else
50
+ @form_text = oidreq.form_markup(realm, return_to, params[:immediate], {'id' => 'openid_form'})
51
+ render
52
+ end
53
+ end
54
+
55
+ def login
56
+ oid = params[:openid_identifier]
57
+ raise(Unauthorized, "Sorry, #{oid} is not an authorized OpenID.") unless is_authorized_openid_identifier?(oid, Chef::Config[:authorized_openid_identifiers])
58
+ raise(Unauthorized, "Sorry, #{oid} is not an authorized OpenID Provider.") unless is_authorized_openid_provider?(oid, Chef::Config[:authorized_openid_providers])
59
+ start
60
+ end
61
+
62
+ def complete
63
+ # FIXME - url_for some action is not necessarily the current URL.
64
+ current_url = absolute_slice_url(:openid_consumer_complete)
65
+ parameters = params.reject{|k,v| k == "controller" || k == "action"}
66
+ oidresp = consumer.complete(parameters, current_url)
67
+ case oidresp.status
68
+ when OpenID::Consumer::FAILURE
69
+ raise BadRequest, "Verification failed: #{oidresp.message}" + (oidresp.display_identifier ? " for identifier '#{oidresp.display_identifier}'" : "")
70
+ when OpenID::Consumer::SUCCESS
71
+ session[:openid] = oidresp.identity_url
72
+ if oidresp.display_identifier =~ /openid\/server\/node\/(.+)$/
73
+ reg_name = $1
74
+ reg = Chef::OpenIDRegistration.load(reg_name)
75
+ Chef::Log.error("#{reg_name} is an admin #{reg.admin}")
76
+ session[:level] = reg.admin ? :admin : :node
77
+ session[:node_name] = $1
78
+ else
79
+ session[:level] = :admin
80
+ end
81
+ redirect_back_or_default(absolute_slice_url(:nodes))
82
+ return "Verification of #{oidresp.display_identifier} succeeded."
83
+ when OpenID::Consumer::SETUP_NEEDED
84
+ return "Immediate request failed - Setup Needed"
85
+ when OpenID::Consumer::CANCEL
86
+ return "OpenID transaction cancelled."
87
+ else
88
+ end
89
+ redirect absolute_slice_url(:openid_consumer)
90
+ end
91
+
92
+ def logout
93
+ [:openid,:level,:node_name].each { |n| session.delete(n) }
94
+ redirect slice_url(:top)
95
+ end
96
+
97
+ private
98
+ def is_authorized_openid_provider?(openid, authorized_providers)
99
+ Chef::Log.debug("checking for valid openid provider: openid: #{openid}, authorized providers: #{authorized_providers}")
100
+ if authorized_providers and openid
101
+ if authorized_providers.length > 0
102
+ authorized_providers.detect { |p| Chef::Log.debug("openid: #{openid} (#{openid.class}), p: #{p} (#{p.class})"); openid.match(p) }
103
+ else
104
+ true
105
+ end
106
+ else
107
+ true
108
+ end
109
+ end
110
+
111
+ def is_authorized_openid_identifier?(openid, authorized_identifiers)
112
+ Chef::Log.debug("checking for valid openid identifier: openid: #{openid}, authorized openids: #{authorized_identifiers}")
113
+ if authorized_identifiers and openid
114
+ if authorized_identifiers.length > 0
115
+ authorized_identifiers.detect { |p| Chef::Log.debug("openid: #{openid} (#{openid.class}), p: #{p} (#{p.class})"); openid == p }
116
+ else
117
+ true
118
+ end
119
+ else
120
+ true
121
+ end
122
+ end
123
+
124
+ def consumer
125
+ @consumer ||= OpenID::Consumer.new(session,
126
+ if Chef::Config[:openid_cstore_couchdb]
127
+ OpenID::Store::CouchDB.new(Chef::Config[:couchdb_url])
128
+ else
129
+ OpenID::Store::Filesystem.new(Chef::Config[:openid_cstore_path])
130
+ end)
131
+ end
132
+
133
+ end
@@ -0,0 +1,113 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'openid'
21
+ require 'chef' / 'openid_registration'
22
+
23
+ class ChefServerSlice::OpenidRegister < ChefServerSlice::Application
24
+
25
+ provides :html, :json
26
+
27
+ before :fix_up_node_id
28
+ before :login_required, :only => [ :index, :update, :destroy, :validate, :admin ]
29
+ before :authorized_node, :only => [ :update, :destroy, :validate, :admin ]
30
+
31
+ def index
32
+ @headers['X-XRDS-Location'] = Chef::Config[:openid_url] + "/openid/server/server/xrds"
33
+ @registered_nodes = Chef::OpenIDRegistration.list(true)
34
+ Chef::Log.debug(@registered_nodes.inspect)
35
+ display @registered_nodes
36
+ end
37
+
38
+ def show
39
+ begin
40
+ @registered_node = Chef::OpenIDRegistration.load(params[:id])
41
+ rescue Net::HTTPServerException => e
42
+ if e.message =~ /^404/
43
+ raise NotFound, "Cannot load node registration for #{params[:id]}"
44
+ else
45
+ raise e
46
+ end
47
+ end
48
+ Chef::Log.debug(@registered_node.inspect)
49
+ display @registered_node
50
+ end
51
+
52
+ def create
53
+ params.has_key?(:id) or raise BadRequest, "You must provide an id to register"
54
+ params.has_key?(:password) or raise BadRequest, "You must provide a password to register"
55
+ if Chef::OpenIDRegistration.has_key?(params[:id])
56
+ raise BadRequest, "You cannot re-register #{params[:id]}!"
57
+ end
58
+ @registered_node = Chef::OpenIDRegistration.new
59
+ @registered_node.name = params[:id]
60
+ @registered_node.set_password(params[:password])
61
+ if Chef::Config[:validation_token]
62
+ if params[:validation_token] == Chef::Config[:validation_token]
63
+ @registered_node.validated = true
64
+ else
65
+ @registered_node.validated = false
66
+ end
67
+ else
68
+ @registered_node.validated = false
69
+ end
70
+ @registered_node.save
71
+ display @registered_node
72
+ end
73
+
74
+ def update
75
+ raise BadRequest, "You cannot update your registration -- delete #{params[:id]} and re-register"
76
+ end
77
+
78
+ def destroy
79
+ begin
80
+ r = Chef::OpenIDRegistration.load(params[:id])
81
+ rescue Exception => e
82
+ raise BadRequest, "Cannot find the registration for #{params[:id]}"
83
+ end
84
+ r.destroy
85
+ if content_type == :html
86
+ redirect slice_url(:registrations)
87
+ else
88
+ display({ :message => "Deleted registration for #{params[:id]}"})
89
+ end
90
+ end
91
+
92
+ def validate
93
+ begin
94
+ r = Chef::OpenIDRegistration.load(params[:id])
95
+ rescue Exception => e
96
+ raise BadRequest, "Cannot find the registration for #{params[:id]}"
97
+ end
98
+ r.validated = r.validated ? false : true
99
+ r.save
100
+ redirect slice_url(:registrations)
101
+ end
102
+
103
+ def admin
104
+ begin
105
+ r = Chef::OpenIDRegistration.load(params[:id])
106
+ rescue Exception => e
107
+ raise BadRequest, "Cannot find the registration for #{params[:id]}"
108
+ end
109
+ r.admin = r.admin ? false : true
110
+ r.save
111
+ redirect slice_url(:registrations)
112
+ end
113
+ end
@@ -0,0 +1,252 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'pathname'
21
+
22
+ # load the openid library, first trying rubygems
23
+ #begin
24
+ # require "rubygems"
25
+ # require_gem "ruby-openid", ">= 1.0"
26
+ #rescue LoadError
27
+ require "openid"
28
+ require "openid/consumer/discovery"
29
+ require 'json'
30
+ require 'chef' / 'openid_registration'
31
+ #end
32
+
33
+ class ChefServerSlice::OpenidServer < ChefServerSlice::Application
34
+
35
+ provides :html, :json
36
+
37
+ include Merb::ChefServerSlice::OpenidServerHelper
38
+ include OpenID::Server
39
+
40
+ layout nil
41
+
42
+ before :fix_up_node_id
43
+ after :dump_cookies_and_session
44
+
45
+ def index
46
+
47
+ oidreq = server.decode_request(params.reject{|k,v| k == "controller" || k == "action"})
48
+
49
+ # no openid.mode was given
50
+ unless oidreq
51
+ return "This is the Chef OpenID server endpoint."
52
+ end
53
+
54
+ oidresp = nil
55
+
56
+ if oidreq.kind_of?(CheckIDRequest)
57
+ identity = oidreq.identity
58
+
59
+ if oidresp
60
+ nil
61
+ elsif self.is_authorized(identity, oidreq.trust_root)
62
+ oidresp = oidreq.answer(true, nil, identity)
63
+ elsif oidreq.immediate
64
+ server_url = slice_url :openid_server
65
+ oidresp = oidreq.answer(false, server_url)
66
+ else
67
+ if content_type == :json
68
+ session[:last_oidreq] = oidreq
69
+ response = { :action => slice_url(:openid_server_decision) }
70
+ return response.to_json
71
+ else
72
+ return show_decision_page(oidreq)
73
+ end
74
+ end
75
+ else
76
+ oidresp = server.handle_request(oidreq)
77
+ end
78
+
79
+ self.render_response(oidresp)
80
+ end
81
+
82
+ def show_decision_page(oidreq, message="Do you trust this site with your identity?")
83
+ session[:last_oidreq] = oidreq
84
+ @oidreq = oidreq
85
+
86
+ if message
87
+ session[:notice] = message
88
+ end
89
+
90
+ render :template => 'openid_server/decide'
91
+ end
92
+
93
+ def node_page
94
+ unless Chef::OpenIDRegistration.has_key?(params[:id])
95
+ raise NotFound, "Cannot find registration for #{params[:id]}"
96
+ end
97
+
98
+ # Yadis content-negotiation: we want to return the xrds if asked for.
99
+ accept = request.env['HTTP_ACCEPT']
100
+
101
+ # This is not technically correct, and should eventually be updated
102
+ # to do real Accept header parsing and logic. Though I expect it will work
103
+ # 99% of the time.
104
+ if accept and accept.include?('application/xrds+xml')
105
+ return node_xrds
106
+ end
107
+
108
+ # content negotiation failed, so just render the user page
109
+ xrds_url = absolute_slice_url(:openid_node_xrds, :id => params[:id])
110
+ identity_page = <<EOS
111
+ <html><head>
112
+ <meta http-equiv="X-XRDS-Location" content="#{xrds_url}" />
113
+ <link rel="openid.server" href="#{absolute_slice_url(:openid_node, :id => params[:id])}" />
114
+ </head><body><p>OpenID identity page for registration #{params[:id]}</p>
115
+ </body></html>
116
+ EOS
117
+
118
+ # Also add the Yadis location header, so that they don't have
119
+ # to parse the html unless absolutely necessary.
120
+ @headers['X-XRDS-Location'] = xrds_url
121
+ render identity_page
122
+ end
123
+
124
+ def node_xrds
125
+ types = [
126
+ OpenID::OPENID_2_0_TYPE,
127
+ OpenID::OPENID_1_0_TYPE
128
+ ]
129
+
130
+ render_xrds(types)
131
+ end
132
+
133
+ def idp_xrds
134
+ types = [
135
+ OpenID::OPENID_IDP_2_0_TYPE,
136
+ ]
137
+
138
+ render_xrds(types)
139
+ end
140
+
141
+ def decision
142
+ oidreq = session[:last_oidreq]
143
+ session[:last_oidreq] = nil
144
+
145
+ if params.has_key?(:cancel)
146
+ Chef::Log.info("Cancelling OpenID Authentication")
147
+ return(redirect(oidreq.cancel_url))
148
+ else
149
+ identity = oidreq.identity
150
+ identity =~ /node\/(.+)$/
151
+ openid_node = Chef::OpenIDRegistration.load($1)
152
+ unless openid_node.validated
153
+ raise Unauthorized, "This nodes registration has not been validated"
154
+ end
155
+ if openid_node.password == encrypt_password(openid_node.salt, params[:password])
156
+ if session[:approvals] and !session[:approvals].include?(oidreq.trust_root)
157
+ session[:approvals] << oidreq.trust_root
158
+ else
159
+ session[:approvals] = [oidreq.trust_root]
160
+ end
161
+ oidresp = oidreq.answer(true, nil, identity)
162
+ return self.render_response(oidresp)
163
+ else
164
+ raise Unauthorized, "Invalid credentials"
165
+ end
166
+ end
167
+ end
168
+
169
+ protected
170
+
171
+ def encrypt_password(salt, password)
172
+ Digest::SHA1.hexdigest("--#{salt}--#{password}--")
173
+ end
174
+
175
+ def server
176
+ if @server.nil?
177
+ server_url = absolute_slice_url(:openid_server)
178
+ if Chef::Config[:openid_store_couchdb]
179
+ require 'openid-store-couchdb'
180
+ store = OpenID::Store::CouchDB.new(Chef::Config[:couchdb_url])
181
+ else
182
+ require 'openid/store/filesystem'
183
+ dir = Chef::Config[:openid_store_path]
184
+ store = OpenID::Store::Filesystem.new(dir)
185
+ end
186
+ @server = Server.new(store, server_url)
187
+ end
188
+ return @server
189
+ end
190
+
191
+ def approved(trust_root)
192
+ return false if session[:approvals].nil?
193
+ return session[:approvals].member?(trust_root)
194
+ end
195
+
196
+ def is_authorized(identity_url, trust_root)
197
+ return (session[:username] and (identity_url == url_for_user) and self.approved(trust_root))
198
+ end
199
+
200
+ def render_xrds(types)
201
+ type_str = ""
202
+
203
+ types.each { |uri|
204
+ type_str += "<Type>#{uri}</Type>\n "
205
+ }
206
+
207
+ yadis = <<EOS
208
+ <?xml version="1.0" encoding="UTF-8"?>
209
+ <xrds:XRDS
210
+ xmlns:xrds="xri://$xrds"
211
+ xmlns="xri://$xrd*($v*2.0)">
212
+ <XRD>
213
+ <Service priority="0">
214
+ #{type_str}
215
+ <URI>#{absolute_slice_url(:openid_server)}</URI>
216
+ </Service>
217
+ </XRD>
218
+ </xrds:XRDS>
219
+ EOS
220
+
221
+ @headers['content-type'] = 'application/xrds+xml'
222
+ render yadis
223
+ end
224
+
225
+ def render_response(oidresp)
226
+ if oidresp.needs_signing
227
+ signed_response = server.signatory.sign(oidresp)
228
+ end
229
+ web_response = server.encode_response(oidresp)
230
+
231
+ case web_response.code
232
+ when HTTP_OK
233
+ @status = 200
234
+ render web_response.body
235
+ when HTTP_REDIRECT
236
+ redirect web_response.headers['location']
237
+ else
238
+ @status = 400
239
+ render web_response.body
240
+ end
241
+ end
242
+
243
+ def dump_cookies_and_session
244
+ unless session.empty? or request.cookies.empty?
245
+ cookie_size = request.cookies.inject(0) {|sum,c| sum + c[1].length }
246
+ c, s = request.cookies.inspect, session.inspect
247
+ Chef::Log.debug("cookie dump (size: #{cookie_size}): #{c}")
248
+ Chef::Log.debug("session dump #{s}")
249
+ end
250
+ end
251
+
252
+ end