chef-server-slice 0.7.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|