diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/chef/knife/osc_user_create.rb | 6 | ||||
-rw-r--r-- | lib/chef/knife/osc_user_delete.rb | 4 | ||||
-rw-r--r-- | lib/chef/knife/osc_user_edit.rb | 6 | ||||
-rw-r--r-- | lib/chef/knife/osc_user_list.rb | 4 | ||||
-rw-r--r-- | lib/chef/knife/osc_user_reregister.rb | 4 | ||||
-rw-r--r-- | lib/chef/knife/osc_user_show.rb | 4 | ||||
-rw-r--r-- | lib/chef/knife/user_create.rb | 6 | ||||
-rw-r--r-- | lib/chef/knife/user_delete.rb | 8 | ||||
-rw-r--r-- | lib/chef/knife/user_edit.rb | 6 | ||||
-rw-r--r-- | lib/chef/knife/user_list.rb | 4 | ||||
-rw-r--r-- | lib/chef/knife/user_reregister.rb | 4 | ||||
-rw-r--r-- | lib/chef/knife/user_show.rb | 4 | ||||
-rw-r--r-- | lib/chef/osc_user.rb | 194 | ||||
-rw-r--r-- | lib/chef/user.rb | 241 | ||||
-rw-r--r-- | lib/chef/user_v1.rb | 335 |
15 files changed, 417 insertions, 413 deletions
diff --git a/lib/chef/knife/osc_user_create.rb b/lib/chef/knife/osc_user_create.rb index c368296040..6c3415473f 100644 --- a/lib/chef/knife/osc_user_create.rb +++ b/lib/chef/knife/osc_user_create.rb @@ -27,7 +27,7 @@ class Chef class OscUserCreate < Knife deps do - require 'chef/osc_user' + require 'chef/user' require 'chef/json_compat' end @@ -69,7 +69,7 @@ class Chef exit 1 end - user = Chef::OscUser.new + user = Chef::User.new user.name(@user_name) user.admin(config[:admin]) user.password config[:user_password] @@ -79,7 +79,7 @@ class Chef end output = edit_data(user) - user = Chef::OscUser.from_hash(output).create + user = Chef::User.from_hash(output).create ui.info("Created #{user}") if user.private_key diff --git a/lib/chef/knife/osc_user_delete.rb b/lib/chef/knife/osc_user_delete.rb index d6fbd4a6a9..5cd4f10413 100644 --- a/lib/chef/knife/osc_user_delete.rb +++ b/lib/chef/knife/osc_user_delete.rb @@ -28,7 +28,7 @@ class Chef class OscUserDelete < Knife deps do - require 'chef/osc_user' + require 'chef/user' require 'chef/json_compat' end @@ -43,7 +43,7 @@ class Chef exit 1 end - delete_object(Chef::OscUser, @user_name) + delete_object(Chef::User, @user_name) end end diff --git a/lib/chef/knife/osc_user_edit.rb b/lib/chef/knife/osc_user_edit.rb index 4c38674d08..526475db05 100644 --- a/lib/chef/knife/osc_user_edit.rb +++ b/lib/chef/knife/osc_user_edit.rb @@ -28,7 +28,7 @@ class Chef class OscUserEdit < Knife deps do - require 'chef/osc_user' + require 'chef/user' require 'chef/json_compat' end @@ -43,10 +43,10 @@ class Chef exit 1 end - original_user = Chef::OscUser.load(@user_name).to_hash + original_user = Chef::User.load(@user_name).to_hash edited_user = edit_data(original_user) if original_user != edited_user - user = Chef::OscUser.from_hash(edited_user) + user = Chef::User.from_hash(edited_user) user.update ui.msg("Saved #{user}.") else diff --git a/lib/chef/knife/osc_user_list.rb b/lib/chef/knife/osc_user_list.rb index 92f049cd19..84fca31899 100644 --- a/lib/chef/knife/osc_user_list.rb +++ b/lib/chef/knife/osc_user_list.rb @@ -28,7 +28,7 @@ class Chef class OscUserList < Knife deps do - require 'chef/osc_user' + require 'chef/user' require 'chef/json_compat' end @@ -40,7 +40,7 @@ class Chef :description => "Show corresponding URIs" def run - output(format_list_for_display(Chef::OscUser.list)) + output(format_list_for_display(Chef::User.list)) end end end diff --git a/lib/chef/knife/osc_user_reregister.rb b/lib/chef/knife/osc_user_reregister.rb index a71e0aa677..163b286fe0 100644 --- a/lib/chef/knife/osc_user_reregister.rb +++ b/lib/chef/knife/osc_user_reregister.rb @@ -28,7 +28,7 @@ class Chef class OscUserReregister < Knife deps do - require 'chef/osc_user' + require 'chef/user' require 'chef/json_compat' end @@ -48,7 +48,7 @@ class Chef exit 1 end - user = Chef::OscUser.load(@user_name).reregister + user = Chef::User.load(@user_name).reregister Chef::Log.debug("Updated user data: #{user.inspect}") key = user.private_key if config[:file] diff --git a/lib/chef/knife/osc_user_show.rb b/lib/chef/knife/osc_user_show.rb index 6a41ddae88..cb3a77585a 100644 --- a/lib/chef/knife/osc_user_show.rb +++ b/lib/chef/knife/osc_user_show.rb @@ -30,7 +30,7 @@ class Chef include Knife::Core::MultiAttributeReturnOption deps do - require 'chef/osc_user' + require 'chef/user' require 'chef/json_compat' end @@ -45,7 +45,7 @@ class Chef exit 1 end - user = Chef::OscUser.load(@user_name) + user = Chef::User.load(@user_name) output(format_for_display(user)) end diff --git a/lib/chef/knife/user_create.rb b/lib/chef/knife/user_create.rb index e73f6be8b6..995573cd03 100644 --- a/lib/chef/knife/user_create.rb +++ b/lib/chef/knife/user_create.rb @@ -27,7 +27,7 @@ class Chef attr_accessor :user_field deps do - require 'chef/user' + require 'chef/user_v1' require 'chef/json_compat' end @@ -61,11 +61,11 @@ class Chef banner "knife user create USERNAME DISPLAY_NAME FIRST_NAME LAST_NAME EMAIL PASSWORD (options)" def user - @user_field ||= Chef::User.new + @user_field ||= Chef::UserV1.new end def create_user_from_hash(hash) - Chef::User.from_hash(hash).create + Chef::UserV1.from_hash(hash).create end def osc_11_warning diff --git a/lib/chef/knife/user_delete.rb b/lib/chef/knife/user_delete.rb index 803be6b90c..828cd51588 100644 --- a/lib/chef/knife/user_delete.rb +++ b/lib/chef/knife/user_delete.rb @@ -23,7 +23,7 @@ class Chef class UserDelete < Knife deps do - require 'chef/user' + require 'chef/user_v1' require 'chef/json_compat' end @@ -55,7 +55,7 @@ EOF if Kernel.block_given? object = block.call else - object = Chef::User.load(user_name) + object = Chef::UserV1.load(user_name) object.destroy end @@ -77,10 +77,10 @@ EOF # Below is modification of Chef::Knife.delete_object to detect OSC 11 server. # When OSC 11 is deprecated, simply delete all this and go back to: # - # delete_object(Chef::User, @user_name) + # delete_object(Chef::UserV1, @user_name) # # Also delete our override of delete_object above - object = Chef::User.load(@user_name) + object = Chef::UserV1.load(@user_name) # OSC 11 case if object.username.nil? diff --git a/lib/chef/knife/user_edit.rb b/lib/chef/knife/user_edit.rb index d194f6697b..c3a4326ee8 100644 --- a/lib/chef/knife/user_edit.rb +++ b/lib/chef/knife/user_edit.rb @@ -23,7 +23,7 @@ class Chef class UserEdit < Knife deps do - require 'chef/user' + require 'chef/user_v1' require 'chef/json_compat' end @@ -56,7 +56,7 @@ EOF exit 1 end - original_user = Chef::User.load(@user_name).to_hash + original_user = Chef::UserV1.load(@user_name).to_hash # DEPRECATION NOTE # Remove this if statement and corrosponding code post OSC 11 support. # @@ -68,7 +68,7 @@ EOF else # EC / CS 12 user create edited_user = edit_data(original_user) if original_user != edited_user - user = Chef::User.from_hash(edited_user) + user = Chef::UserV1.from_hash(edited_user) user.update ui.msg("Saved #{user}.") else diff --git a/lib/chef/knife/user_list.rb b/lib/chef/knife/user_list.rb index 7ae43dadc9..6a130392b9 100644 --- a/lib/chef/knife/user_list.rb +++ b/lib/chef/knife/user_list.rb @@ -25,7 +25,7 @@ class Chef class UserList < Knife deps do - require 'chef/user' + require 'chef/user_v1' require 'chef/json_compat' end @@ -37,7 +37,7 @@ class Chef :description => "Show corresponding URIs" def run - output(format_list_for_display(Chef::User.list)) + output(format_list_for_display(Chef::UserV1.list)) end end diff --git a/lib/chef/knife/user_reregister.rb b/lib/chef/knife/user_reregister.rb index eab2245025..09fd1cd2d6 100644 --- a/lib/chef/knife/user_reregister.rb +++ b/lib/chef/knife/user_reregister.rb @@ -23,7 +23,7 @@ class Chef class UserReregister < Knife deps do - require 'chef/user' + require 'chef/user_v1' require 'chef/json_compat' end @@ -61,7 +61,7 @@ EOF exit 1 end - user = Chef::User.load(@user_name) + user = Chef::UserV1.load(@user_name) # DEPRECATION NOTE # Remove this if statement and corrosponding code post OSC 11 support. diff --git a/lib/chef/knife/user_show.rb b/lib/chef/knife/user_show.rb index f5e81e9972..3a2443471a 100644 --- a/lib/chef/knife/user_show.rb +++ b/lib/chef/knife/user_show.rb @@ -25,7 +25,7 @@ class Chef include Knife::Core::MultiAttributeReturnOption deps do - require 'chef/user' + require 'chef/user_v1' require 'chef/json_compat' end @@ -58,7 +58,7 @@ EOF exit 1 end - user = Chef::User.load(@user_name) + user = Chef::UserV1.load(@user_name) # DEPRECATION NOTE # Remove this if statement and corrosponding code post OSC 11 support. diff --git a/lib/chef/osc_user.rb b/lib/chef/osc_user.rb deleted file mode 100644 index 52bfd11108..0000000000 --- a/lib/chef/osc_user.rb +++ /dev/null @@ -1,194 +0,0 @@ -# -# Author:: Steven Danna (steve@opscode.com) -# Copyright:: Copyright 2012 Opscode, Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -require 'chef/config' -require 'chef/mixin/params_validate' -require 'chef/mixin/from_file' -require 'chef/mash' -require 'chef/json_compat' -require 'chef/search/query' - -# TODO -# DEPRECATION NOTE -# This class was previously Chef::User. It is the code to support the User object -# corrosponding to the Open Source Chef Server 11 and only still exists to support -# users still on OSC 11. -# -# Chef::User now supports Chef Server 12. -# -# New development should occur in Chef::User. -# This file and corrosponding osc_user knife files -# should be removed once client support for Open Source Chef Server 11 expires. -class Chef - class OscUser - - include Chef::Mixin::FromFile - include Chef::Mixin::ParamsValidate - - def initialize - @name = '' - @public_key = nil - @private_key = nil - @password = nil - @admin = false - end - - def name(arg=nil) - set_or_return(:name, arg, - :regex => /^[a-z0-9\-_]+$/) - end - - def admin(arg=nil) - set_or_return(:admin, - arg, :kind_of => [TrueClass, FalseClass]) - end - - def public_key(arg=nil) - set_or_return(:public_key, - arg, :kind_of => String) - end - - def private_key(arg=nil) - set_or_return(:private_key, - arg, :kind_of => String) - end - - def password(arg=nil) - set_or_return(:password, - arg, :kind_of => String) - end - - def to_hash - result = { - "name" => @name, - "public_key" => @public_key, - "admin" => @admin - } - result["private_key"] = @private_key if @private_key - result["password"] = @password if @password - result - end - - def to_json(*a) - Chef::JSONCompat.to_json(to_hash, *a) - end - - def destroy - Chef::REST.new(Chef::Config[:chef_server_url]).delete_rest("users/#{@name}") - end - - def create - payload = {:name => self.name, :admin => self.admin, :password => self.password } - payload[:public_key] = public_key if public_key - new_user =Chef::REST.new(Chef::Config[:chef_server_url]).post_rest("users", payload) - Chef::OscUser.from_hash(self.to_hash.merge(new_user)) - end - - def update(new_key=false) - payload = {:name => name, :admin => admin} - payload[:private_key] = new_key if new_key - payload[:password] = password if password - updated_user = Chef::REST.new(Chef::Config[:chef_server_url]).put_rest("users/#{name}", payload) - Chef::OscUser.from_hash(self.to_hash.merge(updated_user)) - end - - def save(new_key=false) - begin - create - rescue Net::HTTPServerException => e - if e.response.code == "409" - update(new_key) - else - raise e - end - end - end - - def reregister - r = Chef::REST.new(Chef::Config[:chef_server_url]) - reregistered_self = r.put_rest("users/#{name}", { :name => name, :admin => admin, :private_key => true }) - private_key(reregistered_self["private_key"]) - self - end - - def to_s - "user[#{@name}]" - end - - def inspect - "Chef::OscUser name:'#{name}' admin:'#{admin.inspect}'" + - "public_key:'#{public_key}' private_key:#{private_key}" - end - - # Class Methods - - def self.from_hash(user_hash) - user = Chef::OscUser.new - user.name user_hash['name'] - user.private_key user_hash['private_key'] if user_hash.key?('private_key') - user.password user_hash['password'] if user_hash.key?('password') - user.public_key user_hash['public_key'] - user.admin user_hash['admin'] - user - end - - def self.from_json(json) - Chef::OscUser.from_hash(Chef::JSONCompat.from_json(json)) - end - - class << self - alias_method :json_create, :from_json - end - - def self.list(inflate=false) - response = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest('users') - users = if response.is_a?(Array) - transform_ohc_list_response(response) # OHC/OPC - else - response # OSC - end - if inflate - users.inject({}) do |user_map, (name, _url)| - user_map[name] = Chef::OscUser.load(name) - user_map - end - else - users - end - end - - def self.load(name) - response = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("users/#{name}") - Chef::OscUser.from_hash(response) - end - - # Gross. Transforms an API response in the form of: - # [ { "user" => { "username" => USERNAME }}, ...] - # into the form - # { "USERNAME" => "URI" } - def self.transform_ohc_list_response(response) - new_response = Hash.new - response.each do |u| - name = u['user']['username'] - new_response[name] = Chef::Config[:chef_server_url] + "/users/#{name}" - end - new_response - end - - private_class_method :transform_ohc_list_response - end -end diff --git a/lib/chef/user.rb b/lib/chef/user.rb index 717deb63c3..bc9705c092 100644 --- a/lib/chef/user.rb +++ b/lib/chef/user.rb @@ -21,85 +21,44 @@ require 'chef/mixin/from_file' require 'chef/mash' require 'chef/json_compat' require 'chef/search/query' -require 'chef/mixin/api_version_request_handling' -require 'chef/exceptions' -require 'chef/server_api' -# OSC 11 BACKWARDS COMPATIBILITY NOTE (remove after OSC 11 support ends) +# TODO +# DEPRECATION NOTE +# This class will be replaced by Chef::UserV1 in Chef 13. It is the code to support the User object +# corrosponding to the Open Source Chef Server 11 and only still exists to support +# users still on OSC 11. # -# In general, Chef::User is no longer expected to support Open Source Chef 11 Server requests. -# The object that handles those requests has been moved to the Chef::OscUser namespace. +# Chef::UserV1 now supports Chef Server 12 and will be moved to this namespace in Chef 13. # -# Exception: self.list is backwards compatible with OSC 11 +# New development should occur in Chef::UserV1. +# This file and corrosponding osc_user knife files +# should be removed once client support for Open Source Chef Server 11 expires. class Chef class User include Chef::Mixin::FromFile include Chef::Mixin::ParamsValidate - include Chef::Mixin::ApiVersionRequestHandling - - SUPPORTED_API_VERSIONS = [0,1] def initialize - @username = nil - @display_name = nil - @first_name = nil - @middle_name = nil - @last_name = nil - @email = nil - @password = nil + @name = '' @public_key = nil @private_key = nil - @create_key = nil @password = nil + @admin = false end - def chef_root_rest_v0 - @chef_root_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], {:api_version => "0"}) - end - - def chef_root_rest_v1 - @chef_root_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], {:api_version => "1"}) + def chef_rest_v0 + @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"}) end - def username(arg=nil) - set_or_return(:username, arg, + def name(arg=nil) + set_or_return(:name, arg, :regex => /^[a-z0-9\-_]+$/) end - def display_name(arg=nil) - set_or_return(:display_name, - arg, :kind_of => String) - end - - def first_name(arg=nil) - set_or_return(:first_name, - arg, :kind_of => String) - end - - def middle_name(arg=nil) - set_or_return(:middle_name, - arg, :kind_of => String) - end - - def last_name(arg=nil) - set_or_return(:last_name, - arg, :kind_of => String) - end - - def email(arg=nil) - set_or_return(:email, - arg, :kind_of => String) - end - - def password(arg=nil) - set_or_return(:password, - arg, :kind_of => String) - end - - def create_key(arg=nil) - set_or_return(:create_key, arg, - :kind_of => [TrueClass, FalseClass]) + def admin(arg=nil) + set_or_return(:admin, + arg, :kind_of => [TrueClass, FalseClass]) end def public_key(arg=nil) @@ -119,17 +78,12 @@ class Chef def to_hash result = { - "username" => @username + "name" => @name, + "public_key" => @public_key, + "admin" => @admin } - result["display_name"] = @display_name unless @display_name.nil? - result["first_name"] = @first_name unless @first_name.nil? - result["middle_name"] = @middle_name unless @middle_name.nil? - result["last_name"] = @last_name unless @last_name.nil? - result["email"] = @email unless @email.nil? - result["password"] = @password unless @password.nil? - result["public_key"] = @public_key unless @public_key.nil? - result["private_key"] = @private_key unless @private_key.nil? - result["create_key"] = @create_key unless @create_key.nil? + result["private_key"] = @private_key if @private_key + result["password"] = @password if @password result end @@ -138,86 +92,21 @@ class Chef end def destroy - # will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION) - Chef::REST.new(Chef::Config[:chef_server_url]).delete("users/#{@username}") + chef_rest_v0.delete_rest("users/#{@name}") end def create - # try v1, fail back to v0 if v1 not supported - begin - payload = { - :username => @username, - :display_name => @display_name, - :first_name => @first_name, - :last_name => @last_name, - :email => @email, - :password => @password - } - payload[:public_key] = @public_key unless @public_key.nil? - payload[:create_key] = @create_key unless @create_key.nil? - payload[:middle_name] = @middle_name unless @middle_name.nil? - raise Chef::Exceptions::InvalidUserAttribute, "You cannot set both public_key and create_key for create." if !@create_key.nil? && !@public_key.nil? - new_user = chef_root_rest_v1.post("users", payload) - - # get the private_key out of the chef_key hash if it exists - if new_user['chef_key'] - if new_user['chef_key']['private_key'] - new_user['private_key'] = new_user['chef_key']['private_key'] - end - new_user['public_key'] = new_user['chef_key']['public_key'] - new_user.delete('chef_key') - end - rescue Net::HTTPServerException => e - # rescue API V0 if 406 and the server supports V0 - supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS) - raise e unless supported_versions && supported_versions.include?(0) - payload = { - :username => @username, - :display_name => @display_name, - :first_name => @first_name, - :last_name => @last_name, - :email => @email, - :password => @password - } - payload[:middle_name] = @middle_name unless @middle_name.nil? - payload[:public_key] = @public_key unless @public_key.nil? - # under API V0, the server will create a key pair if public_key isn't passed - new_user = chef_root_rest_v0.post("users", payload) - end - + payload = {:name => self.name, :admin => self.admin, :password => self.password } + payload[:public_key] = public_key if public_key + new_user = chef_rest_v0.post_rest("users", payload) Chef::User.from_hash(self.to_hash.merge(new_user)) end def update(new_key=false) - begin - payload = {:username => username} - payload[:display_name] = display_name unless display_name.nil? - payload[:first_name] = first_name unless first_name.nil? - payload[:middle_name] = middle_name unless middle_name.nil? - payload[:last_name] = last_name unless last_name.nil? - payload[:email] = email unless email.nil? - payload[:password] = password unless password.nil? - - # API V1 will fail if these key fields are defined, and try V0 below if relevant 400 is returned - payload[:public_key] = public_key unless public_key.nil? - payload[:private_key] = new_key if new_key - - updated_user = chef_root_rest_v1.put("users/#{username}", payload) - rescue Net::HTTPServerException => e - if e.response.code == "400" - # if a 400 is returned but the error message matches the error related to private / public key fields, try V0 - # else, raise the 400 - error = Chef::JSONCompat.from_json(e.response.body)["error"].first - error_match = /Since Server API v1, all keys must be updated via the keys endpoint/.match(error) - if error_match.nil? - raise e - end - else # for other types of errors, test for API versioning errors right away - supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS) - raise e unless supported_versions && supported_versions.include?(0) - end - updated_user = chef_root_rest_v0.put("users/#{username}", payload) - end + payload = {:name => name, :admin => admin} + payload[:private_key] = new_key if new_key + payload[:password] = password if password + updated_user = chef_rest_v0.put_rest("users/#{name}", payload) Chef::User.from_hash(self.to_hash.merge(updated_user)) end @@ -233,47 +122,30 @@ class Chef end end - # Note: remove after API v0 no longer supported by client (and knife command). def reregister - begin - payload = self.to_hash.merge({"private_key" => true}) - reregistered_self = chef_root_rest_v0.put("users/#{username}", payload) - private_key(reregistered_self["private_key"]) - # only V0 supported for reregister - rescue Net::HTTPServerException => e - # if there was a 406 related to versioning, give error explaining that - # only API version 0 is supported for reregister command - if e.response.code == "406" && e.response["x-ops-server-api-version"] - version_header = Chef::JSONCompat.from_json(e.response["x-ops-server-api-version"]) - min_version = version_header["min_version"] - max_version = version_header["max_version"] - error_msg = reregister_only_v0_supported_error_msg(max_version, min_version) - raise Chef::Exceptions::OnlyApiVersion0SupportedForAction.new(error_msg) - else - raise e - end - end + reregistered_self = chef_rest_v0.put_rest("users/#{name}", { :name => name, :admin => admin, :private_key => true }) + private_key(reregistered_self["private_key"]) self end def to_s - "user[#{@username}]" + "user[#{@name}]" + end + + def inspect + "Chef::User name:'#{name}' admin:'#{admin.inspect}'" + + "public_key:'#{public_key}' private_key:#{private_key}" end # Class Methods def self.from_hash(user_hash) user = Chef::User.new - user.username user_hash['username'] - user.display_name user_hash['display_name'] if user_hash.key?('display_name') - user.first_name user_hash['first_name'] if user_hash.key?('first_name') - user.middle_name user_hash['middle_name'] if user_hash.key?('middle_name') - user.last_name user_hash['last_name'] if user_hash.key?('last_name') - user.email user_hash['email'] if user_hash.key?('email') - user.password user_hash['password'] if user_hash.key?('password') - user.public_key user_hash['public_key'] if user_hash.key?('public_key') + user.name user_hash['name'] user.private_key user_hash['private_key'] if user_hash.key?('private_key') - user.create_key user_hash['create_key'] if user_hash.key?('create_key') + user.password user_hash['password'] if user_hash.key?('password') + user.public_key user_hash['public_key'] + user.admin user_hash['admin'] user end @@ -286,19 +158,12 @@ class Chef end def self.list(inflate=false) - response = Chef::REST.new(Chef::Config[:chef_server_url]).get('users') + response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"}).get_rest('users') users = if response.is_a?(Array) - # EC 11 / CS 12 V0, V1 - # GET /organizations/<org>/users - transform_list_response(response) - else - # OSC 11 - # GET /users - # EC 11 / CS 12 V0, V1 - # GET /users - response # OSC - end - + transform_ohc_list_response(response) # OHC/OPC + else + response # OSC + end if inflate users.inject({}) do |user_map, (name, _url)| user_map[name] = Chef::User.load(name) @@ -309,9 +174,8 @@ class Chef end end - def self.load(username) - # will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION) - response = Chef::REST.new(Chef::Config[:chef_server_url]).get("users/#{username}") + def self.load(name) + response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"}).get_rest("users/#{name}") Chef::User.from_hash(response) end @@ -319,7 +183,7 @@ class Chef # [ { "user" => { "username" => USERNAME }}, ...] # into the form # { "USERNAME" => "URI" } - def self.transform_list_response(response) + def self.transform_ohc_list_response(response) new_response = Hash.new response.each do |u| name = u['user']['username'] @@ -328,7 +192,6 @@ class Chef new_response end - private_class_method :transform_list_response - + private_class_method :transform_ohc_list_response end end diff --git a/lib/chef/user_v1.rb b/lib/chef/user_v1.rb new file mode 100644 index 0000000000..31cb0576a2 --- /dev/null +++ b/lib/chef/user_v1.rb @@ -0,0 +1,335 @@ +# +# Author:: Steven Danna (steve@opscode.com) +# Copyright:: Copyright 2012 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +require 'chef/config' +require 'chef/mixin/params_validate' +require 'chef/mixin/from_file' +require 'chef/mash' +require 'chef/json_compat' +require 'chef/search/query' +require 'chef/mixin/api_version_request_handling' +require 'chef/exceptions' +require 'chef/server_api' + +# OSC 11 BACKWARDS COMPATIBILITY NOTE (remove after OSC 11 support ends) +# +# In general, Chef::UserV1 is no longer expected to support Open Source Chef 11 Server requests. +# The object that handles those requests remain in the Chef::User namespace. +# This code will be moved to the Chef::User namespace as of Chef 13. +# +# Exception: self.list is backwards compatible with OSC 11 +class Chef + class UserV1 + + include Chef::Mixin::FromFile + include Chef::Mixin::ParamsValidate + include Chef::Mixin::ApiVersionRequestHandling + + SUPPORTED_API_VERSIONS = [0,1] + + def initialize + @username = nil + @display_name = nil + @first_name = nil + @middle_name = nil + @last_name = nil + @email = nil + @password = nil + @public_key = nil + @private_key = nil + @create_key = nil + @password = nil + end + + def chef_root_rest_v0 + @chef_root_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], {:api_version => "0"}) + end + + def chef_root_rest_v1 + @chef_root_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], {:api_version => "1"}) + end + + def username(arg=nil) + set_or_return(:username, arg, + :regex => /^[a-z0-9\-_]+$/) + end + + def display_name(arg=nil) + set_or_return(:display_name, + arg, :kind_of => String) + end + + def first_name(arg=nil) + set_or_return(:first_name, + arg, :kind_of => String) + end + + def middle_name(arg=nil) + set_or_return(:middle_name, + arg, :kind_of => String) + end + + def last_name(arg=nil) + set_or_return(:last_name, + arg, :kind_of => String) + end + + def email(arg=nil) + set_or_return(:email, + arg, :kind_of => String) + end + + def password(arg=nil) + set_or_return(:password, + arg, :kind_of => String) + end + + def create_key(arg=nil) + set_or_return(:create_key, arg, + :kind_of => [TrueClass, FalseClass]) + end + + def public_key(arg=nil) + set_or_return(:public_key, + arg, :kind_of => String) + end + + def private_key(arg=nil) + set_or_return(:private_key, + arg, :kind_of => String) + end + + def password(arg=nil) + set_or_return(:password, + arg, :kind_of => String) + end + + def to_hash + result = { + "username" => @username + } + result["display_name"] = @display_name unless @display_name.nil? + result["first_name"] = @first_name unless @first_name.nil? + result["middle_name"] = @middle_name unless @middle_name.nil? + result["last_name"] = @last_name unless @last_name.nil? + result["email"] = @email unless @email.nil? + result["password"] = @password unless @password.nil? + result["public_key"] = @public_key unless @public_key.nil? + result["private_key"] = @private_key unless @private_key.nil? + result["create_key"] = @create_key unless @create_key.nil? + result + end + + def to_json(*a) + Chef::JSONCompat.to_json(to_hash, *a) + end + + def destroy + # will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION) + Chef::REST.new(Chef::Config[:chef_server_url]).delete("users/#{@username}") + end + + def create + # try v1, fail back to v0 if v1 not supported + begin + payload = { + :username => @username, + :display_name => @display_name, + :first_name => @first_name, + :last_name => @last_name, + :email => @email, + :password => @password + } + payload[:public_key] = @public_key unless @public_key.nil? + payload[:create_key] = @create_key unless @create_key.nil? + payload[:middle_name] = @middle_name unless @middle_name.nil? + raise Chef::Exceptions::InvalidUserAttribute, "You cannot set both public_key and create_key for create." if !@create_key.nil? && !@public_key.nil? + new_user = chef_root_rest_v1.post("users", payload) + + # get the private_key out of the chef_key hash if it exists + if new_user['chef_key'] + if new_user['chef_key']['private_key'] + new_user['private_key'] = new_user['chef_key']['private_key'] + end + new_user['public_key'] = new_user['chef_key']['public_key'] + new_user.delete('chef_key') + end + rescue Net::HTTPServerException => e + # rescue API V0 if 406 and the server supports V0 + supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS) + raise e unless supported_versions && supported_versions.include?(0) + payload = { + :username => @username, + :display_name => @display_name, + :first_name => @first_name, + :last_name => @last_name, + :email => @email, + :password => @password + } + payload[:middle_name] = @middle_name unless @middle_name.nil? + payload[:public_key] = @public_key unless @public_key.nil? + # under API V0, the server will create a key pair if public_key isn't passed + new_user = chef_root_rest_v0.post("users", payload) + end + + Chef::UserV1.from_hash(self.to_hash.merge(new_user)) + end + + def update(new_key=false) + begin + payload = {:username => username} + payload[:display_name] = display_name unless display_name.nil? + payload[:first_name] = first_name unless first_name.nil? + payload[:middle_name] = middle_name unless middle_name.nil? + payload[:last_name] = last_name unless last_name.nil? + payload[:email] = email unless email.nil? + payload[:password] = password unless password.nil? + + # API V1 will fail if these key fields are defined, and try V0 below if relevant 400 is returned + payload[:public_key] = public_key unless public_key.nil? + payload[:private_key] = new_key if new_key + + updated_user = chef_root_rest_v1.put("users/#{username}", payload) + rescue Net::HTTPServerException => e + if e.response.code == "400" + # if a 400 is returned but the error message matches the error related to private / public key fields, try V0 + # else, raise the 400 + error = Chef::JSONCompat.from_json(e.response.body)["error"].first + error_match = /Since Server API v1, all keys must be updated via the keys endpoint/.match(error) + if error_match.nil? + raise e + end + else # for other types of errors, test for API versioning errors right away + supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS) + raise e unless supported_versions && supported_versions.include?(0) + end + updated_user = chef_root_rest_v0.put("users/#{username}", payload) + end + Chef::UserV1.from_hash(self.to_hash.merge(updated_user)) + end + + def save(new_key=false) + begin + create + rescue Net::HTTPServerException => e + if e.response.code == "409" + update(new_key) + else + raise e + end + end + end + + # Note: remove after API v0 no longer supported by client (and knife command). + def reregister + begin + payload = self.to_hash.merge({"private_key" => true}) + reregistered_self = chef_root_rest_v0.put("users/#{username}", payload) + private_key(reregistered_self["private_key"]) + # only V0 supported for reregister + rescue Net::HTTPServerException => e + # if there was a 406 related to versioning, give error explaining that + # only API version 0 is supported for reregister command + if e.response.code == "406" && e.response["x-ops-server-api-version"] + version_header = Chef::JSONCompat.from_json(e.response["x-ops-server-api-version"]) + min_version = version_header["min_version"] + max_version = version_header["max_version"] + error_msg = reregister_only_v0_supported_error_msg(max_version, min_version) + raise Chef::Exceptions::OnlyApiVersion0SupportedForAction.new(error_msg) + else + raise e + end + end + self + end + + def to_s + "user[#{@username}]" + end + + # Class Methods + + def self.from_hash(user_hash) + user = Chef::UserV1.new + user.username user_hash['username'] + user.display_name user_hash['display_name'] if user_hash.key?('display_name') + user.first_name user_hash['first_name'] if user_hash.key?('first_name') + user.middle_name user_hash['middle_name'] if user_hash.key?('middle_name') + user.last_name user_hash['last_name'] if user_hash.key?('last_name') + user.email user_hash['email'] if user_hash.key?('email') + user.password user_hash['password'] if user_hash.key?('password') + user.public_key user_hash['public_key'] if user_hash.key?('public_key') + user.private_key user_hash['private_key'] if user_hash.key?('private_key') + user.create_key user_hash['create_key'] if user_hash.key?('create_key') + user + end + + def self.from_json(json) + Chef::UserV1.from_hash(Chef::JSONCompat.from_json(json)) + end + + class << self + alias_method :json_create, :from_json + end + + def self.list(inflate=false) + response = Chef::REST.new(Chef::Config[:chef_server_url]).get('users') + users = if response.is_a?(Array) + # EC 11 / CS 12 V0, V1 + # GET /organizations/<org>/users + transform_list_response(response) + else + # OSC 11 + # GET /users + # EC 11 / CS 12 V0, V1 + # GET /users + response # OSC + end + + if inflate + users.inject({}) do |user_map, (name, _url)| + user_map[name] = Chef::UserV1.load(name) + user_map + end + else + users + end + end + + def self.load(username) + # will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION) + response = Chef::REST.new(Chef::Config[:chef_server_url]).get("users/#{username}") + Chef::UserV1.from_hash(response) + end + + # Gross. Transforms an API response in the form of: + # [ { "user" => { "username" => USERNAME }}, ...] + # into the form + # { "USERNAME" => "URI" } + def self.transform_list_response(response) + new_response = Hash.new + response.each do |u| + name = u['user']['username'] + new_response[name] = Chef::Config[:chef_server_url] + "/users/#{name}" + end + new_response + end + + private_class_method :transform_list_response + + end +end |