chef-server-slice 0.7.10
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 +201 -0
- data/README.rdoc +135 -0
- data/app/controllers/application.rb +228 -0
- data/app/controllers/cookbook_attributes.rb +59 -0
- data/app/controllers/cookbook_definitions.rb +60 -0
- data/app/controllers/cookbook_files.rb +94 -0
- data/app/controllers/cookbook_libraries.rb +60 -0
- data/app/controllers/cookbook_recipes.rb +59 -0
- data/app/controllers/cookbook_templates.rb +80 -0
- data/app/controllers/cookbooks.rb +63 -0
- data/app/controllers/exceptions.rb +33 -0
- data/app/controllers/main.rb +7 -0
- data/app/controllers/nodes.rb +144 -0
- data/app/controllers/openid_consumer.rb +133 -0
- data/app/controllers/openid_register.rb +113 -0
- data/app/controllers/openid_server.rb +252 -0
- data/app/controllers/roles.rb +138 -0
- data/app/controllers/search.rb +58 -0
- data/app/controllers/search_entries.rb +73 -0
- data/app/controllers/status.rb +34 -0
- data/app/helpers/application_helper.rb +144 -0
- data/app/helpers/cookbook_attributes_helper.rb +7 -0
- data/app/helpers/cookbook_definitions_helper.rb +8 -0
- data/app/helpers/cookbook_files_helper.rb +8 -0
- data/app/helpers/cookbook_libraries_helper.rb +7 -0
- data/app/helpers/cookbook_recipes_helper.rb +8 -0
- data/app/helpers/cookbook_templates_helper.rb +8 -0
- data/app/helpers/cookbooks_helper.rb +31 -0
- data/app/helpers/exceptions_helper.rb +6 -0
- data/app/helpers/global_helpers.rb +39 -0
- data/app/helpers/nodes_helper.rb +33 -0
- data/app/helpers/openid_consumer_helper.rb +8 -0
- data/app/helpers/openid_register_helper.rb +8 -0
- data/app/helpers/openid_server_helper.rb +6 -0
- data/app/helpers/openid_server_helpers.rb +29 -0
- data/app/helpers/roles_helper.rb +5 -0
- data/app/helpers/search_entries_helper.rb +8 -0
- data/app/helpers/search_helper.rb +38 -0
- data/app/helpers/status_helper.rb +26 -0
- data/app/views/cookbook_templates/index.html.haml +7 -0
- data/app/views/cookbooks/index.html.haml +10 -0
- data/app/views/cookbooks/show.html.haml +40 -0
- data/app/views/exceptions/bad_request.json.erb +1 -0
- data/app/views/exceptions/internal_server_error.html.erb +216 -0
- data/app/views/exceptions/not_acceptable.html.erb +63 -0
- data/app/views/exceptions/not_found.html.erb +47 -0
- data/app/views/exceptions/standard_error.html.erb +217 -0
- data/app/views/layout/chef_server_slice.html.haml +53 -0
- data/app/views/layout/login.html.haml +37 -0
- data/app/views/main/index.html.erb +1 -0
- data/app/views/nodes/_action.html.haml +13 -0
- data/app/views/nodes/_form.html.haml +56 -0
- data/app/views/nodes/_navigation.html.haml +9 -0
- data/app/views/nodes/_resource.html.haml +22 -0
- data/app/views/nodes/edit.html.haml +7 -0
- data/app/views/nodes/index.html.haml +25 -0
- data/app/views/nodes/new.html.haml +6 -0
- data/app/views/nodes/show.html.haml +60 -0
- data/app/views/openid_consumer/index.html.haml +23 -0
- data/app/views/openid_consumer/start.html.haml +4 -0
- data/app/views/openid_login/index.html.haml +5 -0
- data/app/views/openid_register/index.html.haml +19 -0
- data/app/views/openid_register/show.html.haml +7 -0
- data/app/views/openid_server/decide.html.haml +27 -0
- data/app/views/roles/_form.html.haml +48 -0
- data/app/views/roles/_navigation.html.haml +9 -0
- data/app/views/roles/edit.html.haml +6 -0
- data/app/views/roles/index.html.haml +22 -0
- data/app/views/roles/new.html.haml +6 -0
- data/app/views/roles/show.html.haml +29 -0
- data/app/views/search/_search_form.html.haml +6 -0
- data/app/views/search/index.html.haml +9 -0
- data/app/views/search/show.html.haml +14 -0
- data/app/views/search_entries/index.html.haml +8 -0
- data/app/views/search_entries/show.html.haml +7 -0
- data/app/views/status/index.html.haml +88 -0
- data/config/init.rb +48 -0
- data/config/router.rb +6 -0
- data/lib/chef-server-slice.rb +150 -0
- data/lib/chef-server-slice/merbtasks.rb +103 -0
- data/lib/chef-server-slice/slicetasks.rb +20 -0
- data/lib/chef-server-slice/spectasks.rb +53 -0
- data/public/facebox/README.txt +4 -0
- data/public/facebox/b.png +0 -0
- data/public/facebox/bl.png +0 -0
- data/public/facebox/br.png +0 -0
- data/public/facebox/closelabel.gif +0 -0
- data/public/facebox/facebox.css +95 -0
- data/public/facebox/facebox.js +319 -0
- data/public/facebox/loading.gif +0 -0
- data/public/facebox/tl.png +0 -0
- data/public/facebox/tr.png +0 -0
- data/public/images/avatar.png +0 -0
- data/public/images/black_big.png +0 -0
- data/public/images/indicator.gif +0 -0
- data/public/images/merb.jpg +0 -0
- data/public/images/toggle-collapse-dark.png +0 -0
- data/public/images/toggle-collapse-light.png +0 -0
- data/public/images/toggle-collapse.gif +0 -0
- data/public/images/toggle-expand-dark.png +0 -0
- data/public/images/toggle-expand-light.png +0 -0
- data/public/images/toggle-expand.gif +0 -0
- data/public/images/treeBuilderImages/Thumbs.db +0 -0
- data/public/images/treeBuilderImages/doc.gif +0 -0
- data/public/images/treeBuilderImages/docNode.gif +0 -0
- data/public/images/treeBuilderImages/docNodeLast.gif +0 -0
- data/public/images/treeBuilderImages/docNodeLastFirst.gif +0 -0
- data/public/images/treeBuilderImages/folder.gif +0 -0
- data/public/images/treeBuilderImages/folderNode.gif +0 -0
- data/public/images/treeBuilderImages/folderNodeFirst.gif +0 -0
- data/public/images/treeBuilderImages/folderNodeLast.gif +0 -0
- data/public/images/treeBuilderImages/folderNodeLastFirst.gif +0 -0
- data/public/images/treeBuilderImages/folderNodeOpen.gif +0 -0
- data/public/images/treeBuilderImages/folderNodeOpenFirst.gif +0 -0
- data/public/images/treeBuilderImages/folderNodeOpenLast.gif +0 -0
- data/public/images/treeBuilderImages/folderNodeOpenLastFirst.gif +0 -0
- data/public/images/treeBuilderImages/folderOpen.gif +0 -0
- data/public/images/treeBuilderImages/vertLine.gif +0 -0
- data/public/javascripts/JSONeditor.js +1171 -0
- data/public/javascripts/chef.js +126 -0
- data/public/javascripts/jquery-1.3.2.min.js +19 -0
- data/public/javascripts/jquery-ui-1.7.1.custom.min.js +65 -0
- data/public/javascripts/jquery.editinline.js +108 -0
- data/public/javascripts/jquery.jeditable.mini.js +30 -0
- data/public/javascripts/jquery.livequery.js +250 -0
- data/public/javascripts/jquery.localscroll.js +104 -0
- data/public/javascripts/jquery.scrollTo.js +150 -0
- data/public/javascripts/jquery.tools.min.js +17 -0
- data/public/javascripts/jquery.treeTable.min.js +165 -0
- data/public/stylesheets/base.css +336 -0
- data/public/stylesheets/chef.css +157 -0
- data/public/stylesheets/images/ui-bg_diagonals-small_0_aaaaaa_40x40.png +0 -0
- data/public/stylesheets/images/ui-bg_diagonals-thick_15_444444_40x40.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_100_f0f0f0_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_50_99c2ff_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_55_fbf5d0_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_80_e6e6e6_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_highlight-hard_100_f9f9f9_1x100.png +0 -0
- data/public/stylesheets/images/ui-bg_highlight-soft_100_e7eef3_1x100.png +0 -0
- data/public/stylesheets/images/ui-icons_222222_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_2694e8_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_2e83ff_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_72a7cf_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_888888_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_ffffff_256x240.png +0 -0
- data/public/stylesheets/jquery-ui-1.7.1.custom.css +404 -0
- data/public/stylesheets/jquery.treeTable.css +43 -0
- data/public/stylesheets/themes/bec-green/style.css +290 -0
- data/public/stylesheets/themes/bec/style.css +301 -0
- data/public/stylesheets/themes/blue/style.css +280 -0
- data/public/stylesheets/themes/default/style.css +267 -0
- data/public/stylesheets/themes/djime-cerulean/style.css +298 -0
- data/public/stylesheets/themes/kathleene/style.css +272 -0
- data/public/stylesheets/themes/orange/style.css +263 -0
- data/public/stylesheets/themes/reidb-greenish/style.css +301 -0
- 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,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
|