summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThom May <thom@chef.io>2017-02-01 15:10:25 +0000
committerThom May <thom@chef.io>2017-02-14 15:41:30 -0800
commited3071d2bbd4ca5cafef796b65fc09e564351143 (patch)
tree2f2b1f59398a07537e7fd2661dea1d328afbc2df
parent50d0a6b6a0b55d038fceb3b4047b8b52e5fb110a (diff)
downloadchef-tm/user_refactor.tar.gz
Make UserV0 and UserV1 versioned api classestm/user_refactor
Signed-off-by: Thom May <thom@chef.io>
-rw-r--r--lib/chef/user.rb185
-rw-r--r--lib/chef/user/base.rb123
-rw-r--r--lib/chef/user/v0.rb150
-rw-r--r--lib/chef/user/v1.rb186
-rw-r--r--lib/chef/user_v1.rb328
-rw-r--r--spec/unit/user_spec.rb275
-rw-r--r--spec/unit/user_v0_spec.rb275
-rw-r--r--spec/unit/user_v1_spec.rb54
8 files changed, 771 insertions, 805 deletions
diff --git a/lib/chef/user.rb b/lib/chef/user.rb
index fffaa106f8..3126a15100 100644
--- a/lib/chef/user.rb
+++ b/lib/chef/user.rb
@@ -1,5 +1,4 @@
#
-# Author:: Steven Danna (steve@chef.io)
# Copyright:: Copyright 2012-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
@@ -15,183 +14,21 @@
# 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/server_api"
+require "chef/mixin/versioned_api"
+require "chef/user/user_v0"
+require "chef/user/user_v1"
-# TODO
-# DEPRECATION NOTE
-# This class will be replaced by Chef::UserV1 in Chef 13. It is the code to support the User object
-# corresponding to the Open Source Chef Server 11 and only still exists to support
-# users still on OSC 11.
-#
-# Chef::UserV1 now supports Chef Server 12 and will be moved to this namespace in Chef 13.
-#
-# New development should occur in Chef::UserV1.
-# This file and corresponding osc_user knife files
-# should be removed once client support for Open Source Chef Server 11 expires.
class Chef
class User
+ extend Chef::Mixin::VersionedAPIFactory
- include Chef::Mixin::FromFile
- include Chef::Mixin::ParamsValidate
-
- def initialize
- @name = ""
- @public_key = nil
- @private_key = nil
- @password = nil
- @admin = false
- end
-
- def chef_rest_v0
- @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
- 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_v0.delete("users/#{@name}")
- end
-
- def create
- payload = { :name => name, :admin => admin, :password => password }
- payload[:public_key] = public_key if public_key
- new_user = chef_rest_v0.post("users", payload)
- Chef::User.from_hash(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_v0.put("users/#{name}", payload)
- Chef::User.from_hash(to_hash.merge(updated_user))
- end
-
- def save(new_key = false)
- create
- rescue Net::HTTPServerException => e
- if e.response.code == "409"
- update(new_key)
- else
- raise e
- end
- end
-
- def reregister
- reregistered_self = chef_rest_v0.put("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::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.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::User.from_hash(Chef::JSONCompat.from_json(json))
- end
-
- def self.json_create(json)
- Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::User#from_json or Chef::User#load.")
- Chef::User.from_json(json)
- end
-
- def self.list(inflate = false)
- response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("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::User.load(name)
- user_map
- end
- else
- users
- end
- end
-
- def self.load(name)
- response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("users/#{name}")
- Chef::User.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
+ add_versioned_api_class Chef::User::V0
+ add_versioned_api_class Chef::User::V1
- private_class_method :transform_ohc_list_response
+ def_versioned_delegator :from_json
+ def_versioned_delegator :from_hash
+ def_versioned_delegator :list
+ def_versioned_delegator :load
+ def_versioned_delegator :transform_ohc_list_response
end
end
diff --git a/lib/chef/user/base.rb b/lib/chef/user/base.rb
new file mode 100644
index 0000000000..e12bda38e3
--- /dev/null
+++ b/lib/chef/user/base.rb
@@ -0,0 +1,123 @@
+#
+# Copyright:: Copyright 2012-2017, Chef Software, 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.
+#
+
+class Chef
+ class User
+ class Base
+
+ 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
+ @admin = false
+ end
+
+ def chef_rest
+ @chef_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => @minimum_api_version })
+ end
+
+ def username(arg = nil)
+ set_or_return(:username, arg,
+ :regex => /^[a-z0-9\-_]+$/)
+ end
+ alias name username
+
+ def admin(arg = nil)
+ set_or_return(:admin,
+ arg, :kind_of => [TrueClass, FalseClass])
+ 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 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_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.delete("users/#{@username}")
+ 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 to_s
+ "user[#{@username}]"
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/user/v0.rb b/lib/chef/user/v0.rb
new file mode 100644
index 0000000000..dbc7d7c83f
--- /dev/null
+++ b/lib/chef/user/v0.rb
@@ -0,0 +1,150 @@
+#
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software, 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/mixin/versioned_api"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/server_api"
+require "chef/user/user_base"
+
+# TODO
+# DEPRECATION NOTE
+# This class will be replaced by Chef::UserV1 in Chef 13. It is the code to support the User object
+# corresponding to the Open Source Chef Server 11 and only still exists to support
+# users still on OSC 11.
+#
+# Chef::UserV1 now supports Chef Server 12 and will be moved to this namespace in Chef 13.
+#
+# New development should occur in Chef::UserV1.
+# This file and corresponding osc_user knife files
+# should be removed once client support for Open Source Chef Server 11 expires.
+class Chef
+ class User
+ class V0 < Base
+
+ include Chef::Mixin::FromFile
+ include Chef::Mixin::ParamsValidate
+ extend Chef::Mixin::VersionedAPI
+
+ minimum_api_version 0
+
+ def initialize
+ # Chef.deprecated(:user_v0, "The User API was upgraded, and the old version is scheduled for removal. Please upgrade your Chef Server")
+ super
+ end
+
+ def to_hash
+ result = {
+ "name" => @username,
+ "public_key" => @public_key,
+ "admin" => @admin,
+ }
+ result["private_key"] = @private_key if @private_key
+ result["password"] = @password if @password
+ result
+ 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.post("users", payload)
+ Chef::User::V0.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.put("users/#{name}", payload)
+ Chef::User::V0.from_hash(self.to_hash.merge(updated_user))
+ end
+
+ def reregister
+ reregistered_self = chef_rest.put("users/#{name}", { :name => name, :admin => admin, :private_key => true })
+ private_key(reregistered_self["private_key"])
+ self
+ 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::V0.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::User::V0.from_hash(Chef::JSONCompat.from_json(json))
+ end
+
+ def self.json_create(json)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::User#from_json or Chef::User#load.")
+ Chef::User::V0.from_json(json)
+ end
+
+ def self.list(inflate = false)
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("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::User::V0.load(name)
+ user_map
+ end
+ else
+ users
+ end
+ end
+
+ def self.load(name)
+ response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("users/#{name}")
+ Chef::User::V0.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
+end
diff --git a/lib/chef/user/v1.rb b/lib/chef/user/v1.rb
new file mode 100644
index 0000000000..9cd8363e14
--- /dev/null
+++ b/lib/chef/user/v1.rb
@@ -0,0 +1,186 @@
+#
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software, 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/mixin/versioned_api"
+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"
+require "chef/user/user_base"
+
+# 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 User
+ class V1 < Base
+
+ include Chef::Mixin::FromFile
+ include Chef::Mixin::ParamsValidate
+ extend Chef::Mixin::VersionedAPI
+
+ minimum_api_version 1
+
+ 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 create
+ 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_rest.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
+
+ Chef::User::V1.from_hash(self.to_hash.merge(new_user))
+ end
+
+ def update(new_key = false)
+ 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_rest.put("users/#{username}", payload)
+ Chef::User::V1.from_hash(self.to_hash.merge(updated_user))
+ end
+
+ # Note: remove after API v0 no longer supported by client (and knife command).
+ def reregister
+ error_msg = reregister_only_v0_supported_error_msg(max_version, min_version)
+ raise Chef::Exceptions::OnlyApiVersion0SupportedForAction.new(error_msg)
+ end
+
+ # Class Methods
+
+ def self.from_hash(user_hash)
+ user = Chef::User::V1.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::User::V1.from_hash(Chef::JSONCompat.from_json(json))
+ end
+
+ def self.json_create(json)
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::User::V1#from_json or Chef::User::V1#load.")
+ Chef::User::V1.from_json(json)
+ end
+
+ def self.list(inflate = false)
+ response = Chef::ServerAPI.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::User::V1.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::ServerAPI.new(Chef::Config[:chef_server_url]).get("users/#{username}")
+ Chef::User::V1.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
+end
diff --git a/lib/chef/user_v1.rb b/lib/chef/user_v1.rb
deleted file mode 100644
index b408bbe667..0000000000
--- a/lib/chef/user_v1.rb
+++ /dev/null
@@ -1,328 +0,0 @@
-#
-# Author:: Steven Danna (steve@chef.io)
-# Copyright:: Copyright 2012-2016, Chef Software, 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
- 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 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::ServerAPI.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(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(to_hash.merge(updated_user))
- end
-
- def save(new_key = false)
- create
- rescue Net::HTTPServerException => e
- if e.response.code == "409"
- update(new_key)
- else
- raise e
- end
- end
-
- # Note: remove after API v0 no longer supported by client (and knife command).
- def reregister
- begin
- payload = 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
-
- def self.json_create(json)
- Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::UserV1#from_json or Chef::UserV1#load.")
- Chef::UserV1.from_json(json)
- end
-
- def self.list(inflate = false)
- response = Chef::ServerAPI.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::ServerAPI.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
diff --git a/spec/unit/user_spec.rb b/spec/unit/user_spec.rb
index a1806db987..e69de29bb2 100644
--- a/spec/unit/user_spec.rb
+++ b/spec/unit/user_spec.rb
@@ -1,275 +0,0 @@
-#
-# Author:: Steven Danna (steve@chef.io)
-# Copyright:: Copyright 2012-2016, Chef Software 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.
-#
-
-# DEPRECATION NOTE
-# This code only remains to support users still operating with
-# Open Source Chef Server 11 and should be removed once support
-# for OSC 11 ends. New development should occur in user_spec.rb.
-
-require "spec_helper"
-
-require "chef/user"
-require "tempfile"
-
-describe Chef::User do
- before(:each) do
- @user = Chef::User.new
- end
-
- describe "initialize" do
- it "should be a Chef::User" do
- expect(@user).to be_a_kind_of(Chef::User)
- end
- end
-
- describe "name" do
- it "should let you set the name to a string" do
- expect(@user.name("ops_master")).to eq("ops_master")
- end
-
- it "should return the current name" do
- @user.name "ops_master"
- expect(@user.name).to eq("ops_master")
- end
-
- # It is not feasible to check all invalid characters. Here are a few
- # that we probably care about.
- it "should not accept invalid characters" do
- # capital letters
- expect { @user.name "Bar" }.to raise_error(ArgumentError)
- # slashes
- expect { @user.name "foo/bar" }.to raise_error(ArgumentError)
- # ?
- expect { @user.name "foo?" }.to raise_error(ArgumentError)
- # &
- expect { @user.name "foo&" }.to raise_error(ArgumentError)
- end
-
- it "should not accept spaces" do
- expect { @user.name "ops master" }.to raise_error(ArgumentError)
- end
-
- it "should throw an ArgumentError if you feed it anything but a string" do
- expect { @user.name Hash.new }.to raise_error(ArgumentError)
- end
- end
-
- describe "admin" do
- it "should let you set the admin bit" do
- expect(@user.admin(true)).to eq(true)
- end
-
- it "should return the current admin value" do
- @user.admin true
- expect(@user.admin).to eq(true)
- end
-
- it "should default to false" do
- expect(@user.admin).to eq(false)
- end
-
- it "should throw an ArgumentError if you feed it anything but true or false" do
- expect { @user.name Hash.new }.to raise_error(ArgumentError)
- end
- end
-
- describe "public_key" do
- it "should let you set the public key" do
- expect(@user.public_key("super public")).to eq("super public")
- end
-
- it "should return the current public key" do
- @user.public_key("super public")
- expect(@user.public_key).to eq("super public")
- end
-
- it "should throw an ArgumentError if you feed it something lame" do
- expect { @user.public_key Hash.new }.to raise_error(ArgumentError)
- end
- end
-
- describe "private_key" do
- it "should let you set the private key" do
- expect(@user.private_key("super private")).to eq("super private")
- end
-
- it "should return the private key" do
- @user.private_key("super private")
- expect(@user.private_key).to eq("super private")
- end
-
- it "should throw an ArgumentError if you feed it something lame" do
- expect { @user.private_key Hash.new }.to raise_error(ArgumentError)
- end
- end
-
- describe "when serializing to JSON" do
- before(:each) do
- @user.name("black")
- @user.public_key("crowes")
- @json = @user.to_json
- end
-
- it "serializes as a JSON object" do
- expect(@json).to match(/^\{.+\}$/)
- end
-
- it "includes the name value" do
- expect(@json).to include(%q{"name":"black"})
- end
-
- it "includes the public key value" do
- expect(@json).to include(%{"public_key":"crowes"})
- end
-
- it "includes the 'admin' flag" do
- expect(@json).to include(%q{"admin":false})
- end
-
- it "includes the private key when present" do
- @user.private_key("monkeypants")
- expect(@user.to_json).to include(%q{"private_key":"monkeypants"})
- end
-
- it "does not include the private key if not present" do
- expect(@json).not_to include("private_key")
- end
-
- it "includes the password if present" do
- @user.password "password"
- expect(@user.to_json).to include(%q{"password":"password"})
- end
-
- it "does not include the password if not present" do
- expect(@json).not_to include("password")
- end
-
- include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
- let(:jsonable) { @user }
- end
- end
-
- describe "when deserializing from JSON" do
- before(:each) do
- user = { "name" => "mr_spinks",
- "public_key" => "turtles",
- "private_key" => "pandas",
- "password" => "password",
- "admin" => true }
- @user = Chef::User.from_json(Chef::JSONCompat.to_json(user))
- end
-
- it "should deserialize to a Chef::User object" do
- expect(@user).to be_a_kind_of(Chef::User)
- end
-
- it "preserves the name" do
- expect(@user.name).to eq("mr_spinks")
- end
-
- it "preserves the public key" do
- expect(@user.public_key).to eq("turtles")
- end
-
- it "preserves the admin status" do
- expect(@user.admin).to be_truthy
- end
-
- it "includes the private key if present" do
- expect(@user.private_key).to eq("pandas")
- end
-
- it "includes the password if present" do
- expect(@user.password).to eq("password")
- end
-
- end
-
- describe "API Interactions" do
- before (:each) do
- @user = Chef::User.new
- @user.name "foobar"
- @http_client = double("Chef::ServerAPI mock")
- allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
- end
-
- describe "list" do
- before(:each) do
- Chef::Config[:chef_server_url] = "http://www.example.com"
- @osc_response = { "admin" => "http://www.example.com/users/admin" }
- @ohc_response = [ { "user" => { "username" => "admin" } } ]
- allow(Chef::User).to receive(:load).with("admin").and_return(@user)
- @osc_inflated_response = { "admin" => @user }
- end
-
- it "lists all clients on an OSC server" do
- allow(@http_client).to receive(:get).with("users").and_return(@osc_response)
- expect(Chef::User.list).to eq(@osc_response)
- end
-
- it "inflate all clients on an OSC server" do
- allow(@http_client).to receive(:get).with("users").and_return(@osc_response)
- expect(Chef::User.list(true)).to eq(@osc_inflated_response)
- end
-
- it "lists all clients on an OHC/OPC server" do
- allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
- # We expect that Chef::User.list will give a consistent response
- # so OHC API responses should be transformed to OSC-style output.
- expect(Chef::User.list).to eq(@osc_response)
- end
-
- it "inflate all clients on an OHC/OPC server" do
- allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
- expect(Chef::User.list(true)).to eq(@osc_inflated_response)
- end
- end
-
- describe "create" do
- it "creates a new user via the API" do
- @user.password "password"
- expect(@http_client).to receive(:post).with("users", { :name => "foobar", :admin => false, :password => "password" }).and_return({})
- @user.create
- end
- end
-
- describe "read" do
- it "loads a named user from the API" do
- expect(@http_client).to receive(:get).with("users/foobar").and_return({ "name" => "foobar", "admin" => true, "public_key" => "pubkey" })
- user = Chef::User.load("foobar")
- expect(user.name).to eq("foobar")
- expect(user.admin).to eq(true)
- expect(user.public_key).to eq("pubkey")
- end
- end
-
- describe "update" do
- it "updates an existing user on via the API" do
- expect(@http_client).to receive(:put).with("users/foobar", { :name => "foobar", :admin => false }).and_return({})
- @user.update
- end
- end
-
- describe "destroy" do
- it "deletes the specified user via the API" do
- expect(@http_client).to receive(:delete).with("users/foobar")
- @user.destroy
- end
- end
- end
-end
diff --git a/spec/unit/user_v0_spec.rb b/spec/unit/user_v0_spec.rb
new file mode 100644
index 0000000000..1bc3bbb571
--- /dev/null
+++ b/spec/unit/user_v0_spec.rb
@@ -0,0 +1,275 @@
+#
+# Author:: Steven Danna (steve@chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software 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.
+#
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_spec.rb.
+
+require "spec_helper"
+
+require "chef/user/v0"
+require "tempfile"
+
+describe Chef::User::V0 do
+ before(:each) do
+ @user = Chef::User::V0.new
+ end
+
+ describe "initialize" do
+ it "should be a Chef::User::V0" do
+ expect(@user).to be_a_kind_of(Chef::User::V0)
+ end
+ end
+
+ describe "name" do
+ it "should let you set the name to a string" do
+ expect(@user.name("ops_master")).to eq("ops_master")
+ end
+
+ it "should return the current name" do
+ @user.name "ops_master"
+ expect(@user.name).to eq("ops_master")
+ end
+
+ # It is not feasible to check all invalid characters. Here are a few
+ # that we probably care about.
+ it "should not accept invalid characters" do
+ # capital letters
+ expect { @user.name "Bar" }.to raise_error(ArgumentError)
+ # slashes
+ expect { @user.name "foo/bar" }.to raise_error(ArgumentError)
+ # ?
+ expect { @user.name "foo?" }.to raise_error(ArgumentError)
+ # &
+ expect { @user.name "foo&" }.to raise_error(ArgumentError)
+ end
+
+ it "should not accept spaces" do
+ expect { @user.name "ops master" }.to raise_error(ArgumentError)
+ end
+
+ it "should throw an ArgumentError if you feed it anything but a string" do
+ expect { @user.name Hash.new }.to raise_error(ArgumentError)
+ end
+ end
+
+ describe "admin" do
+ it "should let you set the admin bit" do
+ expect(@user.admin(true)).to eq(true)
+ end
+
+ it "should return the current admin value" do
+ @user.admin true
+ expect(@user.admin).to eq(true)
+ end
+
+ it "should default to false" do
+ expect(@user.admin).to eq(false)
+ end
+
+ it "should throw an ArgumentError if you feed it anything but true or false" do
+ expect { @user.name Hash.new }.to raise_error(ArgumentError)
+ end
+ end
+
+ describe "public_key" do
+ it "should let you set the public key" do
+ expect(@user.public_key("super public")).to eq("super public")
+ end
+
+ it "should return the current public key" do
+ @user.public_key("super public")
+ expect(@user.public_key).to eq("super public")
+ end
+
+ it "should throw an ArgumentError if you feed it something lame" do
+ expect { @user.public_key Hash.new }.to raise_error(ArgumentError)
+ end
+ end
+
+ describe "private_key" do
+ it "should let you set the private key" do
+ expect(@user.private_key("super private")).to eq("super private")
+ end
+
+ it "should return the private key" do
+ @user.private_key("super private")
+ expect(@user.private_key).to eq("super private")
+ end
+
+ it "should throw an ArgumentError if you feed it something lame" do
+ expect { @user.private_key Hash.new }.to raise_error(ArgumentError)
+ end
+ end
+
+ describe "when serializing to JSON" do
+ before(:each) do
+ @user.name("black")
+ @user.public_key("crowes")
+ @json = @user.to_json
+ end
+
+ it "serializes as a JSON object" do
+ expect(@json).to match(/^\{.+\}$/)
+ end
+
+ it "includes the name value" do
+ expect(@json).to include(%q{"name":"black"})
+ end
+
+ it "includes the public key value" do
+ expect(@json).to include(%{"public_key":"crowes"})
+ end
+
+ it "includes the 'admin' flag" do
+ expect(@json).to include(%q{"admin":false})
+ end
+
+ it "includes the private key when present" do
+ @user.private_key("monkeypants")
+ expect(@user.to_json).to include(%q{"private_key":"monkeypants"})
+ end
+
+ it "does not include the private key if not present" do
+ expect(@json).not_to include("private_key")
+ end
+
+ it "includes the password if present" do
+ @user.password "password"
+ expect(@user.to_json).to include(%q{"password":"password"})
+ end
+
+ it "does not include the password if not present" do
+ expect(@json).not_to include("password")
+ end
+
+ include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
+ let(:jsonable) { @user }
+ end
+ end
+
+ describe "when deserializing from JSON" do
+ before(:each) do
+ user = { "name" => "mr_spinks",
+ "public_key" => "turtles",
+ "private_key" => "pandas",
+ "password" => "password",
+ "admin" => true }
+ @user = Chef::User::V0.from_json(Chef::JSONCompat.to_json(user))
+ end
+
+ it "should deserialize to a Chef::User::V0 object" do
+ expect(@user).to be_a_kind_of(Chef::User::V0)
+ end
+
+ it "preserves the name" do
+ expect(@user.name).to eq("mr_spinks")
+ end
+
+ it "preserves the public key" do
+ expect(@user.public_key).to eq("turtles")
+ end
+
+ it "preserves the admin status" do
+ expect(@user.admin).to be_truthy
+ end
+
+ it "includes the private key if present" do
+ expect(@user.private_key).to eq("pandas")
+ end
+
+ it "includes the password if present" do
+ expect(@user.password).to eq("password")
+ end
+
+ end
+
+ describe "API Interactions" do
+ before (:each) do
+ @user = Chef::User::V0.new
+ @user.name "foobar"
+ @http_client = double("Chef::ServerAPI mock")
+ allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
+ end
+
+ describe "list" do
+ before(:each) do
+ Chef::Config[:chef_server_url] = "http://www.example.com"
+ @osc_response = { "admin" => "http://www.example.com/users/admin" }
+ @ohc_response = [ { "user" => { "username" => "admin" } } ]
+ allow(Chef::User::V0).to receive(:load).with("admin").and_return(@user)
+ @osc_inflated_response = { "admin" => @user }
+ end
+
+ it "lists all clients on an OSC server" do
+ allow(@http_client).to receive(:get).with("users").and_return(@osc_response)
+ expect(Chef::User::V0.list).to eq(@osc_response)
+ end
+
+ it "inflate all clients on an OSC server" do
+ allow(@http_client).to receive(:get).with("users").and_return(@osc_response)
+ expect(Chef::User::V0.list(true)).to eq(@osc_inflated_response)
+ end
+
+ it "lists all clients on an OHC/OPC server" do
+ allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
+ # We expect that Chef::User::V0.list will give a consistent response
+ # so OHC API responses should be transformed to OSC-style output.
+ expect(Chef::User::V0.list).to eq(@osc_response)
+ end
+
+ it "inflate all clients on an OHC/OPC server" do
+ allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
+ expect(Chef::User::V0.list(true)).to eq(@osc_inflated_response)
+ end
+ end
+
+ describe "create" do
+ it "creates a new user via the API" do
+ @user.password "password"
+ expect(@http_client).to receive(:post).with("users", { :name => "foobar", :admin => false, :password => "password" }).and_return({})
+ @user.create
+ end
+ end
+
+ describe "read" do
+ it "loads a named user from the API" do
+ expect(@http_client).to receive(:get).with("users/foobar").and_return({ "name" => "foobar", "admin" => true, "public_key" => "pubkey" })
+ user = Chef::User::V0.load("foobar")
+ expect(user.name).to eq("foobar")
+ expect(user.admin).to eq(true)
+ expect(user.public_key).to eq("pubkey")
+ end
+ end
+
+ describe "update" do
+ it "updates an existing user on via the API" do
+ expect(@http_client).to receive(:put).with("users/foobar", { :name => "foobar", :admin => false }).and_return({})
+ @user.update
+ end
+ end
+
+ describe "destroy" do
+ it "deletes the specified user via the API" do
+ expect(@http_client).to receive(:delete).with("users/foobar")
+ @user.destroy
+ end
+ end
+ end
+end
diff --git a/spec/unit/user_v1_spec.rb b/spec/unit/user_v1_spec.rb
index 16f0d0158b..0d2afe8db2 100644
--- a/spec/unit/user_v1_spec.rb
+++ b/spec/unit/user_v1_spec.rb
@@ -18,12 +18,12 @@
require "spec_helper"
-require "chef/user_v1"
+require "chef/user/v1"
require "tempfile"
-describe Chef::UserV1 do
+describe Chef::User::V1 do
before(:each) do
- @user = Chef::UserV1.new
+ @user = Chef::User::V1.new
end
shared_examples_for "string fields with no contraints" do
@@ -62,8 +62,8 @@ describe Chef::UserV1 do
end
describe "initialize" do
- it "should be a Chef::UserV1" do
- expect(@user).to be_a_kind_of(Chef::UserV1)
+ it "should be a Chef::User::V1" do
+ expect(@user).to be_a_kind_of(Chef::User::V1)
end
end
@@ -262,11 +262,11 @@ describe Chef::UserV1 do
"private_key" => "pandas",
"create_key" => false,
}
- @user = Chef::UserV1.from_json(Chef::JSONCompat.to_json(user))
+ @user = Chef::User::V1.from_json(Chef::JSONCompat.to_json(user))
end
- it "should deserialize to a Chef::UserV1 object" do
- expect(@user).to be_a_kind_of(Chef::UserV1)
+ it "should deserialize to a Chef::User::V1 object" do
+ expect(@user).to be_a_kind_of(Chef::User::V1)
end
it "preserves the username" do
@@ -315,9 +315,8 @@ describe Chef::UserV1 do
let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
before (:each) do
- @user = Chef::UserV1.new
- allow(@user).to receive(:chef_root_rest_v0).and_return(double("chef rest root v0 object"))
- allow(@user).to receive(:chef_root_rest_v1).and_return(double("chef rest root v1 object"))
+ @user = Chef::User::V1.new
+ allow(@user).to receive(:chef_rest).and_return(double("chef rest root v1 object"))
end
describe "update" do
@@ -347,7 +346,7 @@ describe Chef::UserV1 do
context "when server API V1 is valid on the Chef Server receiving the request" do
context "when the user submits valid data" do
it "properly updates the user" do
- expect(@user.chef_root_rest_v1).to receive(:put).with("users/some_username", payload).and_return({})
+ expect(@user.chef_rest).to receive(:put).with("users/some_username", payload).and_return({})
@user.update
end
end
@@ -369,7 +368,7 @@ describe Chef::UserV1 do
before do
@user.public_key "some_public_key"
- allow(@user.chef_root_rest_v1).to receive(:put)
+ allow(@user.chef_rest).to receive(:put)
end
context "when the server returns a 400" do
@@ -381,7 +380,7 @@ describe Chef::UserV1 do
before do
allow(response_400).to receive(:body).and_return(response_body_400)
- allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400)
+ allow(@user.chef_rest).to receive(:put).and_raise(exception_400)
end
it "proceeds with the V0 PUT since it can handle public / private key fields" do
@@ -401,7 +400,7 @@ describe Chef::UserV1 do
before do
allow(response_400).to receive(:body).and_return(response_body_400)
- allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400)
+ allow(@user.chef_rest).to receive(:put).and_raise(exception_400)
end
it "will not proceed with the V0 PUT since the original bad request was not key related" do
@@ -422,13 +421,13 @@ describe Chef::UserV1 do
let(:object) { @user }
let(:method) { :update }
let(:http_verb) { :put }
- let(:rest_v1) { @user.chef_root_rest_v1 }
+ let(:rest_v1) { @user.chef_rest }
end
context "when the server supports API V0" do
before do
allow(@user).to receive(:server_client_api_version_intersection).and_return([0])
- allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_406)
+ allow(@user.chef_rest).to receive(:put).and_raise(exception_406)
end
it "properly updates the user" do
@@ -465,15 +464,14 @@ describe Chef::UserV1 do
it_should_behave_like "user or client create" do
let(:object) { @user }
let(:error) { Chef::Exceptions::InvalidUserAttribute }
- let(:rest_v0) { @user.chef_root_rest_v0 }
- let(:rest_v1) { @user.chef_root_rest_v1 }
+ let(:rest_v1) { @user.chef_rest }
let(:url) { "users" }
end
context "when handling API V1" do
it "creates a new user via the API with a middle_name when it exists" do
@user.middle_name "some_middle_name"
- expect(@user.chef_root_rest_v1).to receive(:post).with("users", payload.merge({ :middle_name => "some_middle_name" })).and_return({})
+ expect(@user.chef_rest).to receive(:post).with("users", payload.merge({ :middle_name => "some_middle_name" })).and_return({})
@user.create
end
end # when server API V1 is valid on the Chef Server receiving the request
@@ -484,14 +482,14 @@ describe Chef::UserV1 do
let(:object) { @user }
let(:method) { :create }
let(:http_verb) { :post }
- let(:rest_v1) { @user.chef_root_rest_v1 }
+ let(:rest_v1) { @user.chef_rest }
end
end
context "when handling API V0" do
before do
allow(@user).to receive(:server_client_api_version_intersection).and_return([0])
- allow(@user.chef_root_rest_v1).to receive(:post).and_raise(exception_406)
+ allow(@user.chef_rest).to receive(:post).and_raise(exception_406)
end
it "creates a new user via the API with a middle_name when it exists" do
@@ -536,7 +534,7 @@ describe Chef::UserV1 do
describe "API Interactions" do
before (:each) do
- @user = Chef::UserV1.new
+ @user = Chef::User::V1.new
@user.username "foobar"
@http_client = double("Chef::ServerAPI mock")
allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
@@ -547,27 +545,27 @@ describe Chef::UserV1 do
Chef::Config[:chef_server_url] = "http://www.example.com"
@osc_response = { "admin" => "http://www.example.com/users/admin" }
@ohc_response = [ { "user" => { "username" => "admin" } } ]
- allow(Chef::UserV1).to receive(:load).with("admin").and_return(@user)
+ allow(Chef::User::V1).to receive(:load).with("admin").and_return(@user)
@osc_inflated_response = { "admin" => @user }
end
it "lists all clients on an OHC/OPC server" do
allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
- # We expect that Chef::UserV1.list will give a consistent response
+ # We expect that Chef::User::V1.list will give a consistent response
# so OHC API responses should be transformed to OSC-style output.
- expect(Chef::UserV1.list).to eq(@osc_response)
+ expect(Chef::User::V1.list).to eq(@osc_response)
end
it "inflate all clients on an OHC/OPC server" do
allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
- expect(Chef::UserV1.list(true)).to eq(@osc_inflated_response)
+ expect(Chef::User::V1.list(true)).to eq(@osc_inflated_response)
end
end
describe "read" do
it "loads a named user from the API" do
expect(@http_client).to receive(:get).with("users/foobar").and_return({ "username" => "foobar", "admin" => true, "public_key" => "pubkey" })
- user = Chef::UserV1.load("foobar")
+ user = Chef::User::V1.load("foobar")
expect(user.username).to eq("foobar")
expect(user.public_key).to eq("pubkey")
end