diff options
author | Adam Edwards <adamed@opscode.com> | 2015-12-12 23:04:18 -0800 |
---|---|---|
committer | Bryan McLellan <btm@loftninjas.org> | 2017-09-05 20:09:30 -0400 |
commit | 2e9c29b0658136f0536d423ca71899a825f3920d (patch) | |
tree | 2c84b0369d6e7393d6ec92f83f1c1646074af0b3 | |
parent | 76f6507044162021636f380168e75542ac7d5f20 (diff) | |
download | chef-2e9c29b0658136f0536d423ca71899a825f3920d.tar.gz |
Windows user identity user name and credntial validation
-rw-r--r-- | lib/chef/mixin/user_identity.rb | 81 | ||||
-rw-r--r-- | spec/unit/mixin/user_identity_spec.rb | 201 |
2 files changed, 282 insertions, 0 deletions
diff --git a/lib/chef/mixin/user_identity.rb b/lib/chef/mixin/user_identity.rb new file mode 100644 index 0000000000..6218b44ac2 --- /dev/null +++ b/lib/chef/mixin/user_identity.rb @@ -0,0 +1,81 @@ +# +# Author:: Adam Edwards (<adamed@chef.io>) +# Copyright:: Copyright (c) 2015 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 + module Mixin + module UserIdentity + + def validate_identity(specified_user, password = nil, specified_domain = nil) + validate_identity_platform(specified_user, password, specified_domain) + validate_identity_syntax(specified_user, password, specified_domain) + end + + def validate_identity_platform(specified_user, password = nil, specified_domain = nil) + if ! Chef::Platform.windows? + if password || specified_domain + raise Exceptions::UnsupportedPlatform, "Values for `domain` and `password` are only supported on the Windows platform" + end + else + if specified_user && password.nil? + raise ArgumentError, "A value for `password` must be specified when a value for `user` is specified on the Windows platform" + end + end + end + + def validate_identity_syntax(specified_user, password = nil, specified_domain = nil) + identity = qualify_user(specified_user, specified_domain) + + if ( password || identity[:domain] ) && identity[:user].nil? + raise ArgumentError, "A value for `password` or `domain` was specified without specification of a value for `user`" + end + end + + def qualify_user(specified_user, specified_domain = nil) + domain = specified_domain + user = specified_user + + if specified_user.nil? && ! specified_domain.nil? + raise ArgumentError, "The domain `#{specified_domain}` was specified, but no user name was given" + end + + if ! specified_user.nil? && specified_domain.nil? + domain_and_user = user.split('\\') + + if domain_and_user.length == 1 + domain_and_user = user.split('@') + end + + if domain_and_user.length == 2 + domain = domain_and_user[0] + user = domain_and_user[1] + elsif domain_and_user.length != 1 + raise ArgumentError, "The specified user name `#{user}` is not a syntactically valid user name" + end + end + + { domain: domain, user: user } + end + + protected(:validate_identity) + protected(:validate_identity_platform) + protected(:validate_identity_syntax) + protected(:qualify_user) + + end + end +end diff --git a/spec/unit/mixin/user_identity_spec.rb b/spec/unit/mixin/user_identity_spec.rb new file mode 100644 index 0000000000..f75092f660 --- /dev/null +++ b/spec/unit/mixin/user_identity_spec.rb @@ -0,0 +1,201 @@ +# +# Author:: Adam Edwards (<adamed@chef.io>) +# Copyright:: Copyright (c) 2015 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 'spec_helper' +require 'chef/mixin/user_identity' + +shared_examples_for "it received valid credentials" do + describe "the validation method" do + it "should not raise an error" do + expect {instance_with_identity.validate(username, password, domain)}.not_to raise_error + end + end + + describe "the name qualification method" do + it "should correctly translate the user and domain" do + identity = nil + expect { identity = instance_with_identity.qualify_name(username, domain) }.not_to raise_error + expect(identity[:domain]).to eq(domain) + expect(identity[:user]).to eq(username) + end + end +end + +shared_examples_for "it received invalid credentials" do + describe "the validation method" do + it "should raise an error" do + expect { instance_with_identity.validate(username, password, domain)}.to raise_error(ArgumentError) + end + end +end + +shared_examples_for "it received credentials that are not valid on the platform" do + describe "the validation method" do + it "should raise an error" do + expect { instance_with_identity.validate(username, password, domain)}.to raise_error(Chef::Exceptions::UnsupportedPlatform) + end + end +end + +shared_examples_for "a consumer of the ::Chef::Mixin::UserIdentity mixin" do + context "when running on Windows" do + before do + allow(::Chef::Platform).to receive(:windows?).and_return(true) + end + + context "when no user, domain, or password is specified" do + let(:username) { nil } + let(:domain) { nil } + let(:password) { nil } + it_behaves_like "it received valid credentials" + end + + context "when a valid username is specified" do + let(:username) { 'starchild' } + context "when a valid domain is specified" do + let(:domain) { 'mothership' } + + context "when the password is not specified" do + let(:password) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received valid credentials" + end + end + + context "when the domain is not specified" do + let(:domain) { nil } + + context "when the password is not specified" do + let(:password) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received valid credentials" + end + end + end + + context "when the username is not specified" do + let(:username) { nil } + + context "when the password is specified and the domain is not" do + let(:password) { 'we.funk!' } + let(:domain) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the domain is specified and the password is not" do + let(:domain) { 'mothership' } + let(:password) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the domain and password are specified" do + let(:domain) { 'mothership' } + let(:password) { 'we.funk!' } + it_behaves_like "it received invalid credentials" + end + end + end + + context "when not running on Windows" do + before do + allow(::Chef::Platform).to receive(:windows?).and_return(false) + end + + context "when no user, domain, or password is specified" do + let(:username) { nil } + let(:domain) { nil } + let(:password) { nil } + it_behaves_like "it received valid credentials" + end + + context "when the user is specified and the domain and password are not" do + let(:username) { 'starchild' } + let(:domain) { nil } + let(:password) { nil } + it_behaves_like "it received valid credentials" + + context "when the password is specified and the domain is not" do + let(:password) { 'we.funk!' } + let(:domain) { nil } + it_behaves_like "it received credentials that are not valid on the platform" + end + + context "when the domain is specified and the password is not" do + let(:domain) { 'mothership' } + let(:password) { nil } + it_behaves_like "it received credentials that are not valid on the platform" + end + + context "when the domain and password are specified" do + let(:domain) { 'mothership' } + let(:password) { 'we.funk!' } + it_behaves_like "it received credentials that are not valid on the platform" + end + end + + context "when the user is not specified" do + let(:username) { nil } + context "when the domain is specified" do + let(:domain) { 'mothership' } + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received credentials that are not valid on the platform" + end + + context "when password is not specified" do + let(:password) { nil } + it_behaves_like "it received credentials that are not valid on the platform" + end + end + + context "when the domain is not specified" do + let(:domain) { nil } + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received credentials that are not valid on the platform" + end + end + end + end +end + +describe "a class that mixes in user_identity" do + let(:instance_with_identity) do + class IdentityClass + include ::Chef::Mixin::UserIdentity + def validate(*args) + validate_identity(*args) + end + + def qualify_name(*args) + qualify_user(*args) + end + end + IdentityClass.new + end + + it_behaves_like "a consumer of the ::Chef::Mixin::UserIdentity mixin" +end |