diff --git a/.rubocop.yml b/.rubocop.yml index c4fa194..4afcc01 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,10 +6,14 @@ AllCops: - "integration/**/*" - "spec/**/*" - "test/**/*" -Metrics/ClassLength: - Max: 200 -Metrics/ModuleLength: - Max: 110 Metrics/BlockLength: Exclude: - "googleauth.gemspec" +Metrics/ClassLength: + Max: 200 +Metrics/CyclomaticComplexity: + Max: 15 +Metrics/ModuleLength: + Max: 200 +Metrics/PerceivedComplexity: + Max: 15 diff --git a/lib/googleauth/compute_engine.rb b/lib/googleauth/compute_engine.rb index 2c7ee02..69a729b 100644 --- a/lib/googleauth/compute_engine.rb +++ b/lib/googleauth/compute_engine.rb @@ -80,11 +80,16 @@ def reset_cache alias unmemoize_all reset_cache end + # @private Temporary; remove when universe domain metadata endpoint is stable (see b/349488459). + attr_accessor :disable_universe_domain_check + # Construct a GCECredentials def initialize options = {} # Override the constructor to remember whether the universe domain was # overridden by a constructor argument. @universe_domain_overridden = options["universe_domain"] || options[:universe_domain] ? true : false + # TODO: Remove when universe domain metadata endpoint is stable (see b/349488459). + @disable_universe_domain_check = true super options end @@ -127,20 +132,8 @@ def build_token_hash body, content_type, retrieval_time else Signet::OAuth2.parse_credentials body, content_type end - unless @universe_domain_overridden - universe_domain = Google::Cloud.env.lookup_metadata "universe", "universe_domain" - universe_domain = "googleapis.com" if !universe_domain || universe_domain.empty? - hash["universe_domain"] = universe_domain.strip - end - # The response might have been cached, which means expires_in might be - # stale. Update it based on the time since the data was retrieved. - # We also ensure expires_in is conservative; subtracting at least 1 - # second to offset any skew from metadata server latency. - if hash["expires_in"].is_a? Numeric - offset = 1 + (Process.clock_gettime(Process::CLOCK_MONOTONIC) - retrieval_time).round - hash["expires_in"] -= offset if offset.positive? - hash["expires_in"] = 0 if hash["expires_in"].negative? - end + add_universe_domain_to hash + adjust_for_stale_expires_in hash, retrieval_time hash end @@ -152,6 +145,30 @@ def parse_encoded_token body end hash end + + def add_universe_domain_to hash + return if @universe_domain_overridden + universe_domain = + if disable_universe_domain_check + # TODO: Remove when universe domain metadata endpoint is stable (see b/349488459). + "googleapis.com" + else + Google::Cloud.env.lookup_metadata "universe", "universe_domain" + end + universe_domain = "googleapis.com" if !universe_domain || universe_domain.empty? + hash["universe_domain"] = universe_domain.strip + end + + # The response might have been cached, which means expires_in might be + # stale. Update it based on the time since the data was retrieved. + # We also ensure expires_in is conservative; subtracting at least 1 + # second to offset any skew from metadata server latency. + def adjust_for_stale_expires_in hash, retrieval_time + return unless hash["expires_in"].is_a? Numeric + offset = 1 + (Process.clock_gettime(Process::CLOCK_MONOTONIC) - retrieval_time).round + hash["expires_in"] -= offset if offset.positive? + hash["expires_in"] = 0 if hash["expires_in"].negative? + end end end end diff --git a/lib/googleauth/credentials.rb b/lib/googleauth/credentials.rb index c0061a2..733c89b 100644 --- a/lib/googleauth/credentials.rb +++ b/lib/googleauth/credentials.rb @@ -299,6 +299,12 @@ def self.lookup_local_constant name # attr_reader :quota_project_id + # @private Temporary; remove when universe domain metadata endpoint is stable (see b/349488459). + def disable_universe_domain_check + return false unless @client.respond_to? :disable_universe_domain_check + @client.disable_universe_domain_check + end + # @private Delegate client methods to the client object. extend Forwardable diff --git a/spec/googleauth/compute_engine_spec.rb b/spec/googleauth/compute_engine_spec.rb index ad308ec..44eb5cc 100644 --- a/spec/googleauth/compute_engine_spec.rb +++ b/spec/googleauth/compute_engine_spec.rb @@ -69,86 +69,107 @@ def make_auth_stubs opts end end - context "default universe due to 404 from MDS" do + context "when metadata query is disabled" do + before :example do + @universe_domain = StandardError + end + it_behaves_like "apply/apply! are OK" - it "sets the universe" do + it "leaves universe as googleapis.com and does not call the MDS" do make_auth_stubs access_token: "1/abcde" @client.fetch_access_token! expect(@client.universe_domain).to eq("googleapis.com") end - - it "returns a consistent expiry using cached data" do - make_auth_stubs access_token: "1/abcde" - @client.fetch_access_token! - expiry = @client.expires_at - sleep 1 - @client.fetch_access_token! - expect(@client.expires_at.to_f).to be_within(0.2).of(expiry.to_f) - end end - context "default universe due to empty data from MDS" do + context "when metadata query is enabled" do before :example do - @universe_domain = "" + @client.disable_universe_domain_check = false end - it_behaves_like "apply/apply! are OK" + context "default universe due to 404 from MDS" do + it_behaves_like "apply/apply! are OK" - it "sets the universe" do - make_auth_stubs access_token: "1/abcde" - @client.fetch_access_token! - expect(@client.universe_domain).to eq("googleapis.com") - end + it "sets the universe" do + make_auth_stubs access_token: "1/abcde" + @client.fetch_access_token! + expect(@client.universe_domain).to eq("googleapis.com") + end - it "returns a consistent expiry using cached data" do - make_auth_stubs access_token: "1/abcde" - @client.fetch_access_token! - expiry = @client.expires_at - sleep 1 - @client.fetch_access_token! - expect(@client.expires_at.to_f).to be_within(0.2).of(expiry.to_f) + it "returns a consistent expiry using cached data" do + make_auth_stubs access_token: "1/abcde" + @client.fetch_access_token! + expiry1 = @client.expires_at.to_f + sleep 3 + @client.fetch_access_token! + expiry2 = @client.expires_at.to_f + expect(expiry2).to be_within(1.0).of(expiry1) + end end - end - context "custom universe" do - before :example do - @universe_domain = "myuniverse.com" - end + context "default universe due to empty data from MDS" do + before :example do + @universe_domain = "" + end - it_behaves_like "apply/apply! are OK" + it_behaves_like "apply/apply! are OK" - it "sets the universe" do - make_auth_stubs access_token: "1/abcde" - @client.fetch_access_token! - expect(@client.universe_domain).to eq("myuniverse.com") - end + it "sets the universe" do + make_auth_stubs access_token: "1/abcde" + @client.fetch_access_token! + expect(@client.universe_domain).to eq("googleapis.com") + end - it "supports updating the universe_domain" do - make_auth_stubs access_token: "1/abcde" - @client.fetch_access_token! - @client.universe_domain = "anotheruniverse.com" - expect(@client.universe_domain).to eq("anotheruniverse.com") + it "returns a consistent expiry using cached data" do + make_auth_stubs access_token: "1/abcde" + @client.fetch_access_token! + expiry = @client.expires_at + sleep 3 + @client.fetch_access_token! + expect(@client.expires_at.to_f).to be_within(1.0).of(expiry.to_f) + end end - it "prioritizes argument-specified universe domain" do - make_auth_stubs access_token: "1/abcde" - custom_client = GCECredentials.new universe_domain: "override-universe.com" - custom_client.fetch_access_token! - expect(custom_client.access_token).to eq("1/abcde") - expect(custom_client.universe_domain).to eq("override-universe.com") - end - end + context "custom universe" do + before :example do + @universe_domain = "myuniverse.com" + end - context "error in universe_domain" do - before :example do - @universe_domain = Errno::EHOSTDOWN + it_behaves_like "apply/apply! are OK" + + it "sets the universe" do + make_auth_stubs access_token: "1/abcde" + @client.fetch_access_token! + expect(@client.universe_domain).to eq("myuniverse.com") + end + + it "supports updating the universe_domain" do + make_auth_stubs access_token: "1/abcde" + @client.fetch_access_token! + @client.universe_domain = "anotheruniverse.com" + expect(@client.universe_domain).to eq("anotheruniverse.com") + end + + it "prioritizes argument-specified universe domain" do + make_auth_stubs access_token: "1/abcde" + custom_client = GCECredentials.new universe_domain: "override-universe.com" + custom_client.fetch_access_token! + expect(custom_client.access_token).to eq("1/abcde") + expect(custom_client.universe_domain).to eq("override-universe.com") + end end - it "results in an error" do - make_auth_stubs access_token: "1/abcde" - expect { @client.fetch_access_token! } - .to raise_error Signet::AuthorizationError + context "error in universe_domain" do + before :example do + @universe_domain = Errno::EHOSTDOWN + end + + it "results in an error" do + make_auth_stubs access_token: "1/abcde" + expect { @client.fetch_access_token! } + .to raise_error Signet::AuthorizationError + end end end