diff options
Diffstat (limited to 'packages/chef-server/app')
-rw-r--r-- | packages/chef-server/app/controllers/application.rb | 67 | ||||
-rw-r--r-- | packages/chef-server/app/controllers/nodes.rb | 48 | ||||
-rw-r--r-- | packages/chef-server/app/controllers/openid_consumer.rb | 68 | ||||
-rw-r--r-- | packages/chef-server/app/controllers/openid_register.rb | 91 | ||||
-rw-r--r-- | packages/chef-server/app/controllers/openid_server.rb | 91 | ||||
-rw-r--r-- | packages/chef-server/app/helpers/openid_server_helpers.rb | 2 | ||||
-rw-r--r-- | packages/chef-server/app/views/layout/application.html.haml | 17 | ||||
-rw-r--r-- | packages/chef-server/app/views/nodes/index.html.haml | 4 | ||||
-rw-r--r-- | packages/chef-server/app/views/openid_consumer/start.html.haml (renamed from packages/chef-server/app/views/openid_consumer/start.htmlhaml) | 0 | ||||
-rw-r--r-- | packages/chef-server/app/views/openid_register/index.html.haml | 15 | ||||
-rw-r--r-- | packages/chef-server/app/views/openid_register/show.html.haml | 5 | ||||
-rw-r--r-- | packages/chef-server/app/views/openid_server/decide.html.haml | 12 |
12 files changed, 263 insertions, 157 deletions
diff --git a/packages/chef-server/app/controllers/application.rb b/packages/chef-server/app/controllers/application.rb index 5ce39a0102..4a0d247306 100644 --- a/packages/chef-server/app/controllers/application.rb +++ b/packages/chef-server/app/controllers/application.rb @@ -1,2 +1,69 @@ class Application < Merb::Controller + + def fix_up_node_id + if params.has_key?(:id) + params[:id].gsub!(/_/, '.') + end + end + + def escape_node_id + if params.has_key?(:id) + params[:id].gsub(/_/, '.') + end + end + + def login_required + if session[:openid] + return session[:openid] + else + self.store_location + throw(:halt, :access_denied) + end + end + + def authorized_node + if session[:level] == :admin + Chef::Log.debug("Authorized as Administrator") + true + elsif session[:level] == :node + Chef::Log.debug("Authorized as node") + if session[:node_name] == params[:id].gsub(/\./, '_') + true + else + raise( + Unauthorized, + "You are not the correct node for this action: #{session[:node_name]} instead of #{params[:id]}" + ) + end + else + Chef::Log.debug("Unauthorized") + raise Unauthorized, "You are not allowed to take this action." + end + end + + # Store the URI of the current request in the session. + # + # We can return to this location by calling #redirect_back_or_default. + def store_location + session[:return_to] = request.uri + end + + # Redirect to the URI stored by the most recent store_location call or + # to the passed default. + def redirect_back_or_default(default) + loc = session[:return_to] || default + session[:return_to] = nil + redirect loc + end + + def access_denied + case content_type + when :html + store_location + redirect url(:openid_consumer) + else + raise Unauthorized, "You must authenticate first!" + end + end + end
\ No newline at end of file diff --git a/packages/chef-server/app/controllers/nodes.rb b/packages/chef-server/app/controllers/nodes.rb index 340a981899..aa7273c47d 100644 --- a/packages/chef-server/app/controllers/nodes.rb +++ b/packages/chef-server/app/controllers/nodes.rb @@ -3,27 +3,28 @@ class Nodes < Application provides :html, :json before :fix_up_node_id + before :login_required, :only => [ :create, :update, :destroy ] + before :authorized_node, :only => [ :update, :destroy ] def index - @node_list = Chef::FileStore.list("node") + @node_list = Chef::Node.list display @node_list end def show begin - @node = Chef::FileStore.load("node", params[:id]) - rescue RuntimeError => e - raise BadRequest, "Cannot load node #{params[:id]}" + @node = Chef::Node.load(params[:id]) + rescue Net::HTTPServerException => e + raise NotFound, "Cannot load node #{params[:id]}" end display @node end def create - @node = params.has_key?("inflated_object") ? params["inflated_object"] : nil + @node = params.has_key?("inflated_object") ? params["inflated_object"] : nil if @node @status = 202 - Chef::FileStore.store("node", @node.name, @node) - Chef::Queue.send_msg(:queue, :node_index, @node) + @node.save display @node else raise BadRequest, "You must provide a Node to create" @@ -34,40 +35,33 @@ class Nodes < Application @node = params.has_key?("inflated_object") ? params["inflated_object"] : nil if @node @status = 202 - Chef::FileStore.store("node", @node.name, @node) - Chef::Queue.send_msg(:queue, :node_index, @node) + @node.save display @node else - raise BadRequest, "You must provide a Node to update" + raise NotFound, "You must provide a Node to update" end end def destroy begin - @node = Chef::FileStore.load("node", params[:id]) + @node = Chef::Node.load(params[:id]) rescue RuntimeError => e raise BadRequest, "Node #{params[:id]} does not exist to destroy!" end @status = 202 - Chef::FileStore.delete("node", params[:id]) - Chef::Queue.send_msg(:queue, :node_remove, @node) - display @node + @node.destroy + if content_type == :html + redirect url(:nodes) + else + display @node + end end def compile # Grab a Chef::Compile object compile = Chef::Compile.new() compile.load_node(params[:id]) - - stored_node = Chef::FileStore.load("node", params[:id]) - - stored_node.each_attribute do |field, value| - compile.node[field] = value - end - stored_node.recipes.each do |r| - compile.node.recipes << r unless compile.node.recipes.detect { |h| r == h } - end - Chef::FileStore.store("node", params[:id], compile.node) + compile.node.save compile.load_definitions compile.load_recipes @output = { @@ -77,10 +71,4 @@ class Nodes < Application display @output end - def fix_up_node_id - if params.has_key?(:id) - params[:id].gsub!(/_/, '.') - end - end - end diff --git a/packages/chef-server/app/controllers/openid_consumer.rb b/packages/chef-server/app/controllers/openid_consumer.rb index 58f18445e1..1c8b76296c 100644 --- a/packages/chef-server/app/controllers/openid_consumer.rb +++ b/packages/chef-server/app/controllers/openid_consumer.rb @@ -5,16 +5,18 @@ require 'openid/store/filesystem' class OpenidConsumer < Application + provides :html, :json + def index render end def start + check_valid_openid_provider(params[:openid_identifier]) begin oidreq = consumer.begin(params[:openid_identifier]) rescue OpenID::OpenIDError => e - session[:error] = "Discovery failed for #{params[:openid_identifier]}: #{e}" - return redirect(url(:openid_consumer)) + raise BadRequest, "Discovery failed for #{params[:openid_identifier]}: #{e}" end return_to = absolute_url(:openid_consumer_complete) realm = absolute_url(:openid_consumer) @@ -33,26 +35,58 @@ class OpenidConsumer < Application parameters = params.reject{|k,v| k == "controller" || k == "action"} oidresp = consumer.complete(parameters, current_url) case oidresp.status - when OpenID::Consumer::FAILURE - if oidresp.display_identifier - session[:error] = ("Verification of #{oidresp.display_identifier}"\ - " failed: #{oidresp.message}") + when OpenID::Consumer::FAILURE + if oidresp.display_identifier + raise BadRequest, "Verification of #{oidresp.display_identifier} failed: #{oidresp.message}" + else + raise BadRequest, "Verification failed: #{oidresp.message}" + end + when OpenID::Consumer::SUCCESS + session[:openid] = oidresp.identity_url + if oidresp.display_identifier =~ /openid\/server\/node\/(.+)$/ + session[:level] = :node + session[:node_name] = $1 + else + session[:level] = :admin + end + redirect_back_or_default(absolute_url(:nodes)) + return "Verification of #{oidresp.display_identifier} succeeded." + when OpenID::Consumer::SETUP_NEEDED + return "Immediate request failed - Setup Needed" + when OpenID::Consumer::CANCEL + return "OpenID transaction cancelled." else - session[:error] = "Verification failed: #{oidresp.message}" - end - when OpenID::Consumer::SUCCESS - session[:success] = ("Verification of #{oidresp.display_identifier}"\ - " succeeded.") - when OpenID::Consumer::SETUP_NEEDED - session[:alert] = "Immediate request failed - Setup Needed" - when OpenID::Consumer::CANCEL - session[:alert] = "OpenID transaction cancelled." - else end - redirect url(:openid_consumer) + redirect absolute_url(:openid_consumer) + end + + def logout + session[:openid] = nil if session.has_key?(:openid) + session[:level] = nil if session.has_key?(:level) + session[:node_name] = nil if session.has_key?(:node_name) + redirect url(:top) end private + + # Returns true if the openid is at a valid provider, based on whether :openid_providers is + # defined. Raises an exception if it is not an allowed provider. + def check_valid_openid_provider(openid) + if Chef::Config[:openid_providers] + fp = Chef::Config[:openid_providers].detect do |p| + case openid + when /^http:\/\/#{p}/, /^#{p}/ + true + else + false + end + end + unless fp + raise Unauthorized, "Sorry, #{openid} is not an allowed OpenID Provider." + end + end + true + end def consumer if @consumer.nil? diff --git a/packages/chef-server/app/controllers/openid_register.rb b/packages/chef-server/app/controllers/openid_register.rb index 2636524a2d..a6c30c95c5 100644 --- a/packages/chef-server/app/controllers/openid_register.rb +++ b/packages/chef-server/app/controllers/openid_register.rb @@ -6,39 +6,40 @@ require 'openid' class OpenidRegister < Application provides :html, :json + + before :fix_up_node_id def index - @headers['X-XRDS-Location'] = absolute_url(:controller => "server", :action => "idp_xrds") - @registered_nodes = Chef::FileStore.list("openid_node") + @headers['X-XRDS-Location'] = absolute_url(:controller => "openid_server", :action => "idp_xrds") + @registered_nodes = Chef::OpenIDRegistration.list(true) + Chef::Log.debug(@registered_nodes.inspect) display @registered_nodes end def show begin - @registered_node = Chef::FileStore.load("openid_node", params[:id]) - rescue RuntimeError => e - raise NotFound, "Cannot load node registration for #{params[:id]}" - end + @registered_node = Chef::OpenIDRegistration.load(params[:id]) + rescue Net::HTTPServerException => e + if e.message =~ /^404/ + raise NotFound, "Cannot load node registration for #{params[:id]}" + else + raise e + end + end + Merb.logger.debug(@registered_node.inspect) display @registered_node end def create params.has_key?(:id) or raise BadRequest, "You must provide an id to register" params.has_key?(:password) or raise BadRequest, "You must provide a password to register" - if Chef::FileStore.has_key?("openid_node", params[:id]) + if Chef::OpenIDRegistration.has_key?(params[:id]) raise BadRequest, "You cannot re-register #{params[:id]}!" end - salt = generate_salt - @registered_node = { - :id => params[:id], - :salt => salt, - :password => encrypt_password(salt, params[:password]) - } - Chef::FileStore.store( - "openid_node", - params[:id], - @registered_node - ) + @registered_node = Chef::OpenIDRegistration.new + @registered_node.name = params[:id] + @registered_node.set_password(params[:password]) + @registered_node.save display @registered_node end @@ -47,47 +48,27 @@ class OpenidRegister < Application end def destroy - unless Chef::FileStore.has_key?("openid_node", params[:id]) + begin + r = Chef::OpenIDRegistration.load(params[:id]) + rescue Exception => e raise BadRequest, "Cannot find the registration for #{params[:id]}" end - Chef::FileStore.delete("openid_node", params[:id]) - display({ :message => "Deleted registration for #{params[:id]}"}) - end - - def submit - user = params[:username] - - # if we get a user, log them in by putting their username in - # the session hash. - unless user.nil? - session[:username] = user unless user.nil? - session[:approvals] = [] - session[:notice] = "Your OpenID URL is <b> - #{url(:controller => "openid_server", :action => "user_page", :username => params[:username])} - </b><br/><br/>Proceed to step 2 below." + r.destroy + if content_type == :html + redirect url(:registrations) else - session[:error] = "Sorry, couldn't log you in. Try again." + display({ :message => "Deleted registration for #{params[:id]}"}) end - - redirect url(:openid_login) - end - - def logout - # delete the username from the session hash - session[:username] = nil - session[:approvals] = nil - redirect url(:openid_login) end - - private - def generate_salt - salt = Time.now.to_s - chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a - 1.upto(30) { |i| salt << chars[rand(chars.size-1)] } - salt - end - - def encrypt_password(salt, password) - Digest::SHA1.hexdigest("--#{salt}--#{password}--") + + def validate + begin + r = Chef::OpenIDRegistration.load(params[:id]) + rescue Exception => e + raise BadRequest, "Cannot find the registration for #{params[:id]}" end + r.validated = r.validated ? false : true + r.save + redirect url(:registrations) + end end diff --git a/packages/chef-server/app/controllers/openid_server.rb b/packages/chef-server/app/controllers/openid_server.rb index cfdb4c4169..665af1fb6d 100644 --- a/packages/chef-server/app/controllers/openid_server.rb +++ b/packages/chef-server/app/controllers/openid_server.rb @@ -8,18 +8,23 @@ require 'pathname' require "openid" require "openid/consumer/discovery" require 'openid/store/filesystem' +require 'json' #end class OpenidServer < Application + provides :html, :json + include Merb::OpenidServerHelper include OpenID::Server layout nil + + before :fix_up_node_id def index - - oidreq = server.decode_request(params) + + oidreq = server.decode_request(params.reject{|k,v| k == "controller" || k == "action"}) # no openid.mode was given unless oidreq @@ -29,21 +34,8 @@ class OpenidServer < Application oidresp = nil if oidreq.kind_of?(CheckIDRequest) - identity = oidreq.identity - if oidreq.id_select - if oidreq.immediate - oidresp = oidreq.answer(false) - elsif session[:username].nil? - # The user hasn't logged in. - return show_decision_page(oidreq) - else - # Else, set the identity to the one the user is using. - identity = url_for_user - end - end - if oidresp nil elsif self.is_authorized(identity, oidreq.trust_root) @@ -52,9 +44,14 @@ class OpenidServer < Application server_url = url :openid_server oidresp = oidreq.answer(false, server_url) else - return show_decision_page(oidreq) + if content_type != 'application/json' + session[:last_oidreq] = oidreq + response = { :action => url(:openid_server_decision) } + return response.to_json + else + return show_decision_page(oidreq) + end end - else oidresp = server.handle_request(oidreq) end @@ -73,7 +70,11 @@ class OpenidServer < Application render :template => 'openid_server/decide' end - def user_page + def node_page + unless Chef::OpenIDRegistration.has_key?(params[:id]) + raise NotFound, "Cannot find registration for #{params[:id]}" + end + # Yadis content-negotiation: we want to return the xrds if asked for. accept = request.env['HTTP_ACCEPT'] @@ -81,16 +82,16 @@ class OpenidServer < Application # to do real Accept header parsing and logic. Though I expect it will work # 99% of the time. if accept and accept.include?('application/xrds+xml') - return user_xrds + return node_xrds end # content negotiation failed, so just render the user page - xrds_url = url(:openid_user_xrds, :username => params[:username]) + xrds_url = absolute_url(:openid_node_xrds, :id => params[:id]) identity_page = <<EOS <html><head> <meta http-equiv="X-XRDS-Location" content="#{xrds_url}" /> -<link rel="openid.server" href="#{absolute_url :openid_user, :username}" /> -</head><body><p>OpenID identity page for #{params[:username]}</p> +<link rel="openid.server" href="#{absolute_url(:openid_node, :id => params[:id])}" /> +</head><body><p>OpenID identity page for registration #{params[:id]}</p> </body></html> EOS @@ -100,11 +101,10 @@ EOS render identity_page end - def user_xrds + def node_xrds types = [ OpenID::OPENID_2_0_TYPE, - OpenID::OPENID_1_0_TYPE, - OpenID::SREG_URI, + OpenID::OPENID_1_0_TYPE ] render_xrds(types) @@ -122,37 +122,36 @@ EOS oidreq = session[:last_oidreq] session[:last_oidreq] = nil - if params[:yes].nil? - redirect oidreq.cancel_url - return - else - id_to_send = params[:id_to_send] - + if params.has_key?(:cancel) + Merb.logger.info("Cancelling OpenID Authentication") + return(redirect(oidreq.cancel_url)) + else identity = oidreq.identity - if oidreq.id_select - if id_to_send and id_to_send != "" - session[:username] = id_to_send - session[:approvals] = [] - identity = url_for_user + identity =~ /node\/(.+)$/ + openid_node = Chef::OpenIDRegistration.load($1) + unless openid_node.validated + raise Unauthorized, "This nodes registration has not been validated" + end + if openid_node.password == encrypt_password(openid_node.salt, params[:password]) + if session[:approvals] + session[:approvals] << oidreq.trust_root else - msg = "You must enter a username to in order to send " + - "an identifier to the Relying Party." - return show_decision_page(oidreq, msg) + session[:approvals] = [oidreq.trust_root] end - end - - if session[:approvals] - session[:approvals] << oidreq.trust_root + oidresp = oidreq.answer(true, nil, identity) + return self.render_response(oidresp) else - session[:approvals] = [oidreq.trust_root] + raise Unauthorized, "Invalid credentials" end - oidresp = oidreq.answer(true, nil, identity) - return self.render_response(oidresp) end end protected + def encrypt_password(salt, password) + Digest::SHA1.hexdigest("--#{salt}--#{password}--") + end + def server if @server.nil? server_url = absolute_url(:openid_server) diff --git a/packages/chef-server/app/helpers/openid_server_helpers.rb b/packages/chef-server/app/helpers/openid_server_helpers.rb index 8e595ead01..73be9cab27 100644 --- a/packages/chef-server/app/helpers/openid_server_helpers.rb +++ b/packages/chef-server/app/helpers/openid_server_helpers.rb @@ -2,7 +2,7 @@ module Merb module OpenidServerHelper def url_for_user - url(:openid_user, :username => session[:username]) + url(:openid_node, :username => session[:username]) end end diff --git a/packages/chef-server/app/views/layout/application.html.haml b/packages/chef-server/app/views/layout/application.html.haml index ea9d378ad4..f04f299d2c 100644 --- a/packages/chef-server/app/views/layout/application.html.haml +++ b/packages/chef-server/app/views/layout/application.html.haml @@ -6,10 +6,17 @@ %meta{"http-equiv" => "content-type", :content => "text/html; charset=utf-8" } %link{:rel => "stylesheet", :href => "/stylesheets/master.css", :type => "text/css", :media => "screen", :charset => "utf-8" } %body + .header + %a{:href => url(:nodes) } Nodes + | + %a{:href => url(:registrations)} Registrations + - if session[:openid] + | + %a{:href => url(:openid_consumer_logout)}= "Logout #{h session[:openid]}" + = "(#{session[:level].to_s})" + - else + | + %a{:href => url(:openid_consumer)} Login = catch_content :for_layout - .footer - - if session[:username] - %a{:href => url(:openid_logout)}= "Log Out #{session[:username]}" - %br/ - = absolute_url(:openid_user, :username => session[:username]) +
\ No newline at end of file diff --git a/packages/chef-server/app/views/nodes/index.html.haml b/packages/chef-server/app/views/nodes/index.html.haml index 908f72fab5..667e1c7317 100644 --- a/packages/chef-server/app/views/nodes/index.html.haml +++ b/packages/chef-server/app/views/nodes/index.html.haml @@ -3,3 +3,7 @@ .node %a{ :href => url(:node, { :id => node.gsub(/\./, "_") }) } = node + %form{ :method => "post", :action => url(:node, { :id => node.gsub(/\./, "_") })} + %input{ :type => "hidden", :name => "_method", :value => "delete" } + %input{ :type => "submit", :name => "Delete", :value => "Delete" } +
\ No newline at end of file diff --git a/packages/chef-server/app/views/openid_consumer/start.htmlhaml b/packages/chef-server/app/views/openid_consumer/start.html.haml index 75ed9a9257..75ed9a9257 100644 --- a/packages/chef-server/app/views/openid_consumer/start.htmlhaml +++ b/packages/chef-server/app/views/openid_consumer/start.html.haml diff --git a/packages/chef-server/app/views/openid_register/index.html.haml b/packages/chef-server/app/views/openid_register/index.html.haml new file mode 100644 index 0000000000..fe4798c59d --- /dev/null +++ b/packages/chef-server/app/views/openid_register/index.html.haml @@ -0,0 +1,15 @@ +%h1 Registered OpenID Nodes List +%table +- @registered_nodes.each do |node| + %tr + %td + %a{ :href => url(:registration, { :id => node.name }) } + = h node.name + %td + - if session[:level] == :admin + %form{ :method => "post", :action => url(:validate_registration, { :id => node.name })} + - submit_name = node.validated ? "Invalidate" : "Validate" + %input{ :type => "submit", :name => submit_name, :value => submit_name } + %form{ :method => "post", :action => url(:registration, { :id => node.name })} + %input{ :type => "hidden", :name => "_method", :value => "delete" } + %input{ :type => "submit", :name => "Delete", :value => "Delete" } diff --git a/packages/chef-server/app/views/openid_register/show.html.haml b/packages/chef-server/app/views/openid_register/show.html.haml new file mode 100644 index 0000000000..cfd38e8963 --- /dev/null +++ b/packages/chef-server/app/views/openid_register/show.html.haml @@ -0,0 +1,5 @@ +%h1= "Registered OpenID Node #{@registered_node.name}" +%ol + %li + %a{ :href => url(:openid_node , { :id => @registered_node.name.gsub(/\./, "_") }) } OpenID URL + %li= "Validated: #{@registered_node.validated}" diff --git a/packages/chef-server/app/views/openid_server/decide.html.haml b/packages/chef-server/app/views/openid_server/decide.html.haml index 78b0b60881..8082a5068d 100644 --- a/packages/chef-server/app/views/openid_server/decide.html.haml +++ b/packages/chef-server/app/views/openid_server/decide.html.haml @@ -8,7 +8,7 @@ %td{:colspan => "2"} You entered the server identifier at the relying party. You will need to send an identifier of your choosing. - Enter a username below. + Enter a username and password below. %tr %td Identity to send: %td @@ -17,5 +17,11 @@ %tr %td Identity: %td= @oidreq.identity - %input{:type => "submit", :name => "yes", :value => "yes"} - %input{:type => "submit", :name => "no", :value => "no"}
\ No newline at end of file + %tr + %td + %label{:for => "password"} Password: + %td + %input{:type => "password", :name => "password"} + %input{:type => "submit", :name => "submit", :value => "Authenticate"} + %input{:type => "submit", :name => "cancel", :value => "Cancel"} + |