googleauth 0.1.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +7 -0
- data/.github/CONTRIBUTING.md +74 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
- data/.github/ISSUE_TEMPLATE/support_request.md +7 -0
- data/.github/workflows/ci.yml +55 -0
- data/.github/workflows/release-please.yml +39 -0
- data/.gitignore +3 -0
- data/.kokoro/populate-secrets.sh +76 -0
- data/.kokoro/release.cfg +52 -0
- data/.kokoro/release.sh +18 -0
- data/.kokoro/trampoline_v2.sh +489 -0
- data/.repo-metadata.json +5 -0
- data/.rubocop.yml +17 -0
- data/.toys/.toys.rb +45 -0
- data/.toys/ci.rb +43 -0
- data/.toys/kokoro/.toys.rb +66 -0
- data/.toys/kokoro/publish-docs.rb +67 -0
- data/.toys/kokoro/publish-gem.rb +53 -0
- data/.toys/linkinator.rb +43 -0
- data/.trampolinerc +48 -0
- data/CHANGELOG.md +192 -0
- data/CODE_OF_CONDUCT.md +43 -0
- data/Gemfile +22 -1
- data/{COPYING → LICENSE} +0 -0
- data/README.md +140 -17
- data/googleauth.gemspec +28 -28
- data/integration/helper.rb +31 -0
- data/integration/id_tokens/key_source_test.rb +74 -0
- data/lib/googleauth.rb +7 -37
- data/lib/googleauth/application_default.rb +81 -0
- data/lib/googleauth/client_id.rb +104 -0
- data/lib/googleauth/compute_engine.rb +73 -26
- data/lib/googleauth/credentials.rb +561 -0
- data/lib/googleauth/credentials_loader.rb +207 -0
- data/lib/googleauth/default_credentials.rb +93 -0
- data/lib/googleauth/iam.rb +75 -0
- data/lib/googleauth/id_tokens.rb +233 -0
- data/lib/googleauth/id_tokens/errors.rb +71 -0
- data/lib/googleauth/id_tokens/key_sources.rb +396 -0
- data/lib/googleauth/id_tokens/verifier.rb +142 -0
- data/lib/googleauth/json_key_reader.rb +50 -0
- data/lib/googleauth/scope_util.rb +61 -0
- data/lib/googleauth/service_account.rb +175 -67
- data/lib/googleauth/signet.rb +69 -8
- data/lib/googleauth/stores/file_token_store.rb +65 -0
- data/lib/googleauth/stores/redis_token_store.rb +96 -0
- data/lib/googleauth/token_store.rb +69 -0
- data/lib/googleauth/user_authorizer.rb +285 -0
- data/lib/googleauth/user_refresh.rb +129 -0
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +295 -0
- data/spec/googleauth/apply_auth_examples.rb +96 -94
- data/spec/googleauth/client_id_spec.rb +160 -0
- data/spec/googleauth/compute_engine_spec.rb +125 -55
- data/spec/googleauth/credentials_spec.rb +600 -0
- data/spec/googleauth/get_application_default_spec.rb +232 -80
- data/spec/googleauth/iam_spec.rb +80 -0
- data/spec/googleauth/scope_util_spec.rb +77 -0
- data/spec/googleauth/service_account_spec.rb +422 -68
- data/spec/googleauth/signet_spec.rb +101 -25
- data/spec/googleauth/stores/file_token_store_spec.rb +57 -0
- data/spec/googleauth/stores/redis_token_store_spec.rb +50 -0
- data/spec/googleauth/stores/store_examples.rb +58 -0
- data/spec/googleauth/user_authorizer_spec.rb +343 -0
- data/spec/googleauth/user_refresh_spec.rb +359 -0
- data/spec/googleauth/web_user_authorizer_spec.rb +172 -0
- data/spec/spec_helper.rb +51 -10
- data/test/helper.rb +33 -0
- data/test/id_tokens/key_sources_test.rb +240 -0
- data/test/id_tokens/verifier_test.rb +269 -0
- metadata +112 -75
- data/.travis.yml +0 -18
- data/CONTRIBUTING.md +0 -32
- data/Rakefile +0 -15
| @@ -0,0 +1,160 @@ | |
| 1 | 
            +
            # Copyright 2015, Google Inc.
         | 
| 2 | 
            +
            # All rights reserved.
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # Redistribution and use in source and binary forms, with or without
         | 
| 5 | 
            +
            # modification, are permitted provided that the following conditions are
         | 
| 6 | 
            +
            # met:
         | 
| 7 | 
            +
            #
         | 
| 8 | 
            +
            #     * Redistributions of source code must retain the above copyright
         | 
| 9 | 
            +
            # notice, this list of conditions and the following disclaimer.
         | 
| 10 | 
            +
            #     * Redistributions in binary form must reproduce the above
         | 
| 11 | 
            +
            # copyright notice, this list of conditions and the following disclaimer
         | 
| 12 | 
            +
            # in the documentation and/or other materials provided with the
         | 
| 13 | 
            +
            # distribution.
         | 
| 14 | 
            +
            #     * Neither the name of Google Inc. nor the names of its
         | 
| 15 | 
            +
            # contributors may be used to endorse or promote products derived from
         | 
| 16 | 
            +
            # this software without specific prior written permission.
         | 
| 17 | 
            +
            #
         | 
| 18 | 
            +
            # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
         | 
| 19 | 
            +
            # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
         | 
| 20 | 
            +
            # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
         | 
| 21 | 
            +
            # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
         | 
| 22 | 
            +
            # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
         | 
| 23 | 
            +
            # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
         | 
| 24 | 
            +
            # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
         | 
| 25 | 
            +
            # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
         | 
| 26 | 
            +
            # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
         | 
| 27 | 
            +
            # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
         | 
| 28 | 
            +
            # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            spec_dir = File.expand_path File.join(File.dirname(__FILE__))
         | 
| 31 | 
            +
            $LOAD_PATH.unshift spec_dir
         | 
| 32 | 
            +
            $LOAD_PATH.uniq!
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            require "spec_helper"
         | 
| 35 | 
            +
            require "fakefs/safe"
         | 
| 36 | 
            +
            require "googleauth"
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            describe Google::Auth::ClientId do
         | 
| 39 | 
            +
              shared_examples "it has a valid config" do
         | 
| 40 | 
            +
                it "should include a valid id" do
         | 
| 41 | 
            +
                  expect(client_id.id).to eql "abc@example.com"
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                it "should include a valid secret" do
         | 
| 45 | 
            +
                  expect(client_id.secret).to eql "notasecret"
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              shared_examples "it can successfully load client_id" do
         | 
| 50 | 
            +
                context "loaded from hash" do
         | 
| 51 | 
            +
                  let(:client_id) { Google::Auth::ClientId.from_hash config }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  it_behaves_like "it has a valid config"
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                context "loaded from file" do
         | 
| 57 | 
            +
                  file_path = "/client_secrets.json"
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  let :client_id do
         | 
| 60 | 
            +
                    FakeFS do
         | 
| 61 | 
            +
                      content = MultiJson.dump config
         | 
| 62 | 
            +
                      File.write file_path, content
         | 
| 63 | 
            +
                      Google::Auth::ClientId.from_file file_path
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  it_behaves_like "it has a valid config"
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              describe "with web config" do
         | 
| 72 | 
            +
                let :config do
         | 
| 73 | 
            +
                  {
         | 
| 74 | 
            +
                    "web" => {
         | 
| 75 | 
            +
                      "client_id"     => "abc@example.com",
         | 
| 76 | 
            +
                      "client_secret" => "notasecret"
         | 
| 77 | 
            +
                    }
         | 
| 78 | 
            +
                  }
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
                it_behaves_like "it can successfully load client_id"
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              describe "with installed app config" do
         | 
| 84 | 
            +
                let :config do
         | 
| 85 | 
            +
                  {
         | 
| 86 | 
            +
                    "installed" => {
         | 
| 87 | 
            +
                      "client_id"     => "abc@example.com",
         | 
| 88 | 
            +
                      "client_secret" => "notasecret"
         | 
| 89 | 
            +
                    }
         | 
| 90 | 
            +
                  }
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
                it_behaves_like "it can successfully load client_id"
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
              context "with missing top level property" do
         | 
| 96 | 
            +
                let :config do
         | 
| 97 | 
            +
                  {
         | 
| 98 | 
            +
                    "notvalid" => {
         | 
| 99 | 
            +
                      "client_id"     => "abc@example.com",
         | 
| 100 | 
            +
                      "client_secret" => "notasecret"
         | 
| 101 | 
            +
                    }
         | 
| 102 | 
            +
                  }
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                it "should raise error" do
         | 
| 106 | 
            +
                  expect { Google::Auth::ClientId.from_hash config }.to raise_error(
         | 
| 107 | 
            +
                    /Expected top level property/
         | 
| 108 | 
            +
                  )
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              context "with missing client id" do
         | 
| 113 | 
            +
                let :config do
         | 
| 114 | 
            +
                  {
         | 
| 115 | 
            +
                    "web" => {
         | 
| 116 | 
            +
                      "client_secret" => "notasecret"
         | 
| 117 | 
            +
                    }
         | 
| 118 | 
            +
                  }
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                it "should raise error" do
         | 
| 122 | 
            +
                  expect { Google::Auth::ClientId.from_hash config }.to raise_error(
         | 
| 123 | 
            +
                    /Client id can not be nil/
         | 
| 124 | 
            +
                  )
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              context "with missing client secret" do
         | 
| 129 | 
            +
                let :config do
         | 
| 130 | 
            +
                  {
         | 
| 131 | 
            +
                    "web" => {
         | 
| 132 | 
            +
                      "client_id" => "abc@example.com"
         | 
| 133 | 
            +
                    }
         | 
| 134 | 
            +
                  }
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                it "should raise error" do
         | 
| 138 | 
            +
                  expect { Google::Auth::ClientId.from_hash config }.to raise_error(
         | 
| 139 | 
            +
                    /Client secret can not be nil/
         | 
| 140 | 
            +
                  )
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
              end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
              context "with cloud sdk credentials" do
         | 
| 145 | 
            +
                let :config do
         | 
| 146 | 
            +
                  {
         | 
| 147 | 
            +
                    "web" => {
         | 
| 148 | 
            +
                      "client_id"     => Google::Auth::CredentialsLoader::CLOUD_SDK_CLIENT_ID,
         | 
| 149 | 
            +
                      "client_secret" => "notasecret"
         | 
| 150 | 
            +
                    }
         | 
| 151 | 
            +
                  }
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                it "should raise warning" do
         | 
| 155 | 
            +
                  expect { Google::Auth::ClientId.from_hash config }.to output(
         | 
| 156 | 
            +
                    Google::Auth::CredentialsLoader::CLOUD_SDK_CREDENTIALS_WARNING + "\n"
         | 
| 157 | 
            +
                  ).to_stderr
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
            end
         | 
| @@ -27,82 +27,152 @@ | |
| 27 27 | 
             
            # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
         | 
| 28 28 | 
             
            # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         | 
| 29 29 |  | 
| 30 | 
            -
            spec_dir = File.expand_path | 
| 31 | 
            -
            $LOAD_PATH.unshift | 
| 30 | 
            +
            spec_dir = File.expand_path File.join(File.dirname(__FILE__))
         | 
| 31 | 
            +
            $LOAD_PATH.unshift spec_dir
         | 
| 32 32 | 
             
            $LOAD_PATH.uniq!
         | 
| 33 33 |  | 
| 34 | 
            -
            require  | 
| 35 | 
            -
            require  | 
| 36 | 
            -
            require  | 
| 37 | 
            -
            require  | 
| 34 | 
            +
            require "apply_auth_examples"
         | 
| 35 | 
            +
            require "faraday"
         | 
| 36 | 
            +
            require "googleauth/compute_engine"
         | 
| 37 | 
            +
            require "spec_helper"
         | 
| 38 38 |  | 
| 39 39 | 
             
            describe Google::Auth::GCECredentials do
         | 
| 40 | 
            -
               | 
| 40 | 
            +
              MD_ACCESS_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
         | 
| 41 | 
            +
              MD_ID_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://pubsub.googleapis.com/&format=full".freeze
         | 
| 41 42 | 
             
              GCECredentials = Google::Auth::GCECredentials
         | 
| 42 43 |  | 
| 43 | 
            -
              before | 
| 44 | 
            +
              before :example do
         | 
| 44 45 | 
             
                @client = GCECredentials.new
         | 
| 46 | 
            +
                @id_client = GCECredentials.new target_audience: "https://pubsub.googleapis.com/"
         | 
| 45 47 | 
             
              end
         | 
| 46 48 |  | 
| 47 | 
            -
              def make_auth_stubs | 
| 48 | 
            -
                 | 
| 49 | 
            -
                   | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
                   | 
| 49 | 
            +
              def make_auth_stubs opts
         | 
| 50 | 
            +
                if opts[:access_token]
         | 
| 51 | 
            +
                  body = MultiJson.dump("access_token" => opts[:access_token],
         | 
| 52 | 
            +
                                        "token_type"   => "Bearer",
         | 
| 53 | 
            +
                                        "expires_in"   => 3600)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  uri = MD_ACCESS_URI
         | 
| 56 | 
            +
                  uri += "?scopes=#{Array(opts[:scope]).join ','}" if opts[:scope]
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  stub_request(:get, uri)
         | 
| 59 | 
            +
                    .with(headers: { "Metadata-Flavor" => "Google" })
         | 
| 60 | 
            +
                    .to_return(body:    body,
         | 
| 61 | 
            +
                               status:  200,
         | 
| 62 | 
            +
                               headers: { "Content-Type" => "application/json" })
         | 
| 63 | 
            +
                elsif opts[:id_token]
         | 
| 64 | 
            +
                  stub_request(:get, MD_ID_URI)
         | 
| 65 | 
            +
                    .with(headers: { "Metadata-Flavor" => "Google" })
         | 
| 66 | 
            +
                    .to_return(body:    opts[:id_token],
         | 
| 67 | 
            +
                               status:  200,
         | 
| 68 | 
            +
                               headers: { "Content-Type" => "text/html" })
         | 
| 57 69 | 
             
                end
         | 
| 58 70 | 
             
              end
         | 
| 59 71 |  | 
| 60 | 
            -
              it_behaves_like  | 
| 72 | 
            +
              it_behaves_like "apply/apply! are OK"
         | 
| 61 73 |  | 
| 62 | 
            -
               | 
| 63 | 
            -
                 | 
| 64 | 
            -
                   | 
| 65 | 
            -
                     | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
                     | 
| 74 | 
            +
              context "metadata is unavailable" do
         | 
| 75 | 
            +
                describe "#fetch_access_token" do
         | 
| 76 | 
            +
                  it "should pass scopes when requesting an access token" do
         | 
| 77 | 
            +
                    scopes = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/bigtable.data"]
         | 
| 78 | 
            +
                    stub = make_auth_stubs access_token: "1/abcdef1234567890", scope: scopes
         | 
| 79 | 
            +
                    @client = GCECredentials.new(scope: scopes)
         | 
| 80 | 
            +
                    @client.fetch_access_token!
         | 
| 81 | 
            +
                    expect(stub).to have_been_requested
         | 
| 70 82 | 
             
                  end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 83 | 
            +
             | 
| 84 | 
            +
                  it "should fail if the metadata request returns a 404" do
         | 
| 85 | 
            +
                    stub = stub_request(:get, MD_ACCESS_URI)
         | 
| 86 | 
            +
                           .to_return(status:  404,
         | 
| 87 | 
            +
                                      headers: { "Metadata-Flavor" => "Google" })
         | 
| 88 | 
            +
                    expect { @client.fetch_access_token! }
         | 
| 89 | 
            +
                      .to raise_error Signet::AuthorizationError
         | 
| 90 | 
            +
                    expect(stub).to have_been_requested
         | 
| 73 91 | 
             
                  end
         | 
| 74 | 
            -
                  expect(GCECredentials.on_gce?(connection: c)).to eq(true)
         | 
| 75 | 
            -
                  stubs.verify_stubbed_calls
         | 
| 76 | 
            -
                end
         | 
| 77 92 |  | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
                     | 
| 93 | 
            +
                  it "should fail if the metadata request returns a 403" do
         | 
| 94 | 
            +
                    stub = stub_request(:get, MD_ACCESS_URI)
         | 
| 95 | 
            +
                             .to_return(status:  403,
         | 
| 96 | 
            +
                                        headers: { "Metadata-Flavor" => "Google" })
         | 
| 97 | 
            +
                    expect { @client.fetch_access_token! }
         | 
| 98 | 
            +
                      .to raise_error Signet::AuthorizationError
         | 
| 99 | 
            +
                    expect(stub).to have_been_requested.times(6)
         | 
| 85 100 | 
             
                  end
         | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 101 | 
            +
             | 
| 102 | 
            +
                  it "should fail if the metadata request returns a 500" do
         | 
| 103 | 
            +
                    stub = stub_request(:get, MD_ACCESS_URI)
         | 
| 104 | 
            +
                             .to_return(status:  500,
         | 
| 105 | 
            +
                                        headers: { "Metadata-Flavor" => "Google" })
         | 
| 106 | 
            +
                    expect { @client.fetch_access_token! }
         | 
| 107 | 
            +
                      .to raise_error Signet::AuthorizationError
         | 
| 108 | 
            +
                    expect(stub).to have_been_requested.times(6)
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  it "should fail if the metadata request returns an unexpected code" do
         | 
| 112 | 
            +
                    stub = stub_request(:get, MD_ACCESS_URI)
         | 
| 113 | 
            +
                           .to_return(status:  503,
         | 
| 114 | 
            +
                                      headers: { "Metadata-Flavor" => "Google" })
         | 
| 115 | 
            +
                    expect { @client.fetch_access_token! }
         | 
| 116 | 
            +
                      .to raise_error Signet::AuthorizationError
         | 
| 117 | 
            +
                    expect(stub).to have_been_requested
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  it "should fail with Signet::AuthorizationError if request times out" do
         | 
| 121 | 
            +
                    allow_any_instance_of(Faraday::Connection).to receive(:get)
         | 
| 122 | 
            +
                      .and_raise(Faraday::TimeoutError)
         | 
| 123 | 
            +
                    expect { @client.fetch_access_token! }
         | 
| 124 | 
            +
                      .to raise_error Signet::AuthorizationError
         | 
| 88 125 | 
             
                  end
         | 
| 89 | 
            -
                  expect(GCECredentials.on_gce?(connection: c)).to eq(false)
         | 
| 90 | 
            -
                  stubs.verify_stubbed_calls
         | 
| 91 | 
            -
                end
         | 
| 92 126 |  | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
                       '']
         | 
| 99 | 
            -
                    end
         | 
| 127 | 
            +
                  it "should fail with Signet::AuthorizationError if request fails" do
         | 
| 128 | 
            +
                    allow_any_instance_of(Faraday::Connection).to receive(:get)
         | 
| 129 | 
            +
                      .and_raise(Faraday::ConnectionFailed, nil)
         | 
| 130 | 
            +
                    expect { @client.fetch_access_token! }
         | 
| 131 | 
            +
                      .to raise_error Signet::AuthorizationError
         | 
| 100 132 | 
             
                  end
         | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              describe "#on_gce?" do
         | 
| 137 | 
            +
                it "should be true when Metadata-Flavor is Google" do
         | 
| 138 | 
            +
                  stub = stub_request(:get, "http://169.254.169.254")
         | 
| 139 | 
            +
                         .with(headers: { "Metadata-Flavor" => "Google" })
         | 
| 140 | 
            +
                         .to_return(status:  200,
         | 
| 141 | 
            +
                                    headers: { "Metadata-Flavor" => "Google" })
         | 
| 142 | 
            +
                  expect(GCECredentials.on_gce?({}, true)).to eq(true)
         | 
| 143 | 
            +
                  expect(stub).to have_been_requested
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                it "should be false when Metadata-Flavor is not Google" do
         | 
| 147 | 
            +
                  stub = stub_request(:get, "http://169.254.169.254")
         | 
| 148 | 
            +
                         .with(headers: { "Metadata-Flavor" => "Google" })
         | 
| 149 | 
            +
                         .to_return(status:  200,
         | 
| 150 | 
            +
                                    headers: { "Metadata-Flavor" => "NotGoogle" })
         | 
| 151 | 
            +
                  expect(GCECredentials.on_gce?({}, true)).to eq(false)
         | 
| 152 | 
            +
                  expect(stub).to have_been_requested
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                it "should be false if the response is not 200" do
         | 
| 156 | 
            +
                  stub = stub_request(:get, "http://169.254.169.254")
         | 
| 157 | 
            +
                         .with(headers: { "Metadata-Flavor" => "Google" })
         | 
| 158 | 
            +
                         .to_return(status:  404,
         | 
| 159 | 
            +
                                    headers: { "Metadata-Flavor" => "NotGoogle" })
         | 
| 160 | 
            +
                  expect(GCECredentials.on_gce?({}, true)).to eq(false)
         | 
| 161 | 
            +
                  expect(stub).to have_been_requested
         | 
| 162 | 
            +
                end
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                it "should honor GCE_METADATA_HOST environment variable" do
         | 
| 165 | 
            +
                  ENV["GCE_METADATA_HOST"] = "mymetadata.example.com"
         | 
| 166 | 
            +
                  begin
         | 
| 167 | 
            +
                    stub = stub_request(:get, "http://mymetadata.example.com")
         | 
| 168 | 
            +
                           .with(headers: { "Metadata-Flavor" => "Google" })
         | 
| 169 | 
            +
                           .to_return(status:  200,
         | 
| 170 | 
            +
                                      headers: { "Metadata-Flavor" => "Google" })
         | 
| 171 | 
            +
                    expect(GCECredentials.on_gce?({}, true)).to eq(true)
         | 
| 172 | 
            +
                    expect(stub).to have_been_requested
         | 
| 173 | 
            +
                  ensure
         | 
| 174 | 
            +
                    ENV.delete "GCE_METADATA_HOST"
         | 
| 103 175 | 
             
                  end
         | 
| 104 | 
            -
                  expect(GCECredentials.on_gce?(connection: c)).to eq(false)
         | 
| 105 | 
            -
                  stubs.verify_stubbed_calls
         | 
| 106 176 | 
             
                end
         | 
| 107 177 | 
             
              end
         | 
| 108 178 | 
             
            end
         | 
| @@ -0,0 +1,600 @@ | |
| 1 | 
            +
            # Copyright 2017, Google Inc.
         | 
| 2 | 
            +
            # All rights reserved.
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # Redistribution and use in source and binary forms, with or without
         | 
| 5 | 
            +
            # modification, are permitted provided that the following conditions are
         | 
| 6 | 
            +
            # met:
         | 
| 7 | 
            +
            #
         | 
| 8 | 
            +
            #     * Redistributions of source code must retain the above copyright
         | 
| 9 | 
            +
            # notice, this list of conditions and the following disclaimer.
         | 
| 10 | 
            +
            #     * Redistributions in binary form must reproduce the above
         | 
| 11 | 
            +
            # copyright notice, this list of conditions and the following disclaimer
         | 
| 12 | 
            +
            # in the documentation and/or other materials provided with the
         | 
| 13 | 
            +
            # distribution.
         | 
| 14 | 
            +
            #     * Neither the name of Google Inc. nor the names of its
         | 
| 15 | 
            +
            # contributors may be used to endorse or promote products derived from
         | 
| 16 | 
            +
            # this software without specific prior written permission.
         | 
| 17 | 
            +
            #
         | 
| 18 | 
            +
            # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
         | 
| 19 | 
            +
            # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
         | 
| 20 | 
            +
            # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
         | 
| 21 | 
            +
            # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
         | 
| 22 | 
            +
            # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
         | 
| 23 | 
            +
            # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
         | 
| 24 | 
            +
            # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
         | 
| 25 | 
            +
            # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
         | 
| 26 | 
            +
            # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
         | 
| 27 | 
            +
            # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
         | 
| 28 | 
            +
            # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            require "googleauth"
         | 
| 31 | 
            +
             | 
| 32 | 
            +
             | 
| 33 | 
            +
            # This test is testing the private class Google::Auth::Credentials. We want to
         | 
| 34 | 
            +
            # make sure that the passed in scope propogates to the Signet object. This means
         | 
| 35 | 
            +
            # testing the private API, which is generally frowned on.
         | 
| 36 | 
            +
            describe Google::Auth::Credentials, :private do
         | 
| 37 | 
            +
              let :default_keyfile_hash do
         | 
| 38 | 
            +
                {
         | 
| 39 | 
            +
                  "private_key_id"   => "testabc1234567890xyz",
         | 
| 40 | 
            +
                  "private_key"      => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
         | 
| 41 | 
            +
                  "client_email"     => "credz-testabc1234567890xyz@developer.gserviceaccount.com",
         | 
| 42 | 
            +
                  "client_id"        => "credz-testabc1234567890xyz.apps.googleusercontent.com",
         | 
| 43 | 
            +
                  "type"             => "service_account",
         | 
| 44 | 
            +
                  "project_id"       => "a_project_id",
         | 
| 45 | 
            +
                  "quota_project_id" => "b_project_id"
         | 
| 46 | 
            +
                }
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              def mock_signet
         | 
| 50 | 
            +
                mocked_signet = double "Signet::OAuth2::Client"
         | 
| 51 | 
            +
                allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
         | 
| 52 | 
            +
                allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
         | 
| 53 | 
            +
                allow(mocked_signet).to receive(:client_id)
         | 
| 54 | 
            +
                allow(Signet::OAuth2::Client).to receive(:new) do |options|
         | 
| 55 | 
            +
                  yield options if block_given?
         | 
| 56 | 
            +
                  mocked_signet
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
                mocked_signet
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              it "uses a default scope" do
         | 
| 62 | 
            +
                mock_signet do |options|
         | 
| 63 | 
            +
                  expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 64 | 
            +
                  expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 65 | 
            +
                  expect(options[:scope]).to eq([])
         | 
| 66 | 
            +
                  expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
         | 
| 67 | 
            +
                  expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                Google::Auth::Credentials.new default_keyfile_hash
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              it "uses a custom scope" do
         | 
| 74 | 
            +
                mock_signet do |options|
         | 
| 75 | 
            +
                  expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 76 | 
            +
                  expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 77 | 
            +
                  expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 78 | 
            +
                  expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
         | 
| 79 | 
            +
                  expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                Google::Auth::Credentials.new default_keyfile_hash, scope: "http://example.com/scope"
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              it "uses empty paths and env_vars by default" do
         | 
| 86 | 
            +
                expect(Google::Auth::Credentials.paths).to eq([])
         | 
| 87 | 
            +
                expect(Google::Auth::Credentials.env_vars).to eq([])
         | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
              describe "using CONSTANTS" do
         | 
| 91 | 
            +
                it "can be subclassed to pass in other env paths" do
         | 
| 92 | 
            +
                  test_path_env_val = "/unknown/path/to/file.txt".freeze
         | 
| 93 | 
            +
                  test_json_env_val = JSON.generate default_keyfile_hash
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  ENV["TEST_PATH"] = test_path_env_val
         | 
| 96 | 
            +
                  ENV["TEST_JSON_VARS"] = test_json_env_val
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  class TestCredentials1 < Google::Auth::Credentials
         | 
| 99 | 
            +
                    TOKEN_CREDENTIAL_URI = "https://example.com/token".freeze
         | 
| 100 | 
            +
                    AUDIENCE = "https://example.com/audience".freeze
         | 
| 101 | 
            +
                    SCOPE = "http://example.com/scope".freeze
         | 
| 102 | 
            +
                    PATH_ENV_VARS = ["TEST_PATH"].freeze
         | 
| 103 | 
            +
                    JSON_ENV_VARS = ["TEST_JSON_VARS"].freeze
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                  allow(::File).to receive(:file?).with(test_path_env_val) { false }
         | 
| 107 | 
            +
                  allow(::File).to receive(:file?).with(test_json_env_val) { false }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  mocked_signet = mock_signet
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 112 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://example.com/token")
         | 
| 113 | 
            +
                    expect(options[:audience]).to eq("https://example.com/audience")
         | 
| 114 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 115 | 
            +
                    expect(options[:enable_self_signed_jwt]).to eq(true)
         | 
| 116 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 117 | 
            +
                    expect(options[:json_key_io].read).to eq(test_json_env_val)
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 120 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 121 | 
            +
                    default_keyfile_hash
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                  creds = TestCredentials1.default enable_self_signed_jwt: true
         | 
| 125 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials1)
         | 
| 126 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 127 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 128 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                it "subclasses can use PATH_ENV_VARS to get keyfile path" do
         | 
| 132 | 
            +
                  class TestCredentials2 < Google::Auth::Credentials
         | 
| 133 | 
            +
                    SCOPE = "http://example.com/scope".freeze
         | 
| 134 | 
            +
                    PATH_ENV_VARS = %w[PATH_ENV_DUMMY PATH_ENV_TEST].freeze
         | 
| 135 | 
            +
                    JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
         | 
| 136 | 
            +
                    DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  json_content = JSON.generate default_keyfile_hash
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 142 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 143 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 144 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
         | 
| 145 | 
            +
                  allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
         | 
| 146 | 
            +
                  allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { json_content }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  mocked_signet = mock_signet
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 151 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 152 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 153 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 154 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 155 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 156 | 
            +
                    expect(options[:json_key_io].read).to eq(json_content)
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 159 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 160 | 
            +
                    default_keyfile_hash
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  creds = TestCredentials2.default
         | 
| 164 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials2)
         | 
| 165 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 166 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 167 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
         | 
| 171 | 
            +
                  test_json_env_val = JSON.generate default_keyfile_hash
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                  class TestCredentials3 < Google::Auth::Credentials
         | 
| 174 | 
            +
                    SCOPE = "http://example.com/scope".freeze
         | 
| 175 | 
            +
                    PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
         | 
| 176 | 
            +
                    JSON_ENV_VARS = %w[JSON_ENV_DUMMY JSON_ENV_TEST].freeze
         | 
| 177 | 
            +
                    DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
         | 
| 178 | 
            +
                  end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 181 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 182 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 183 | 
            +
                  allow(::File).to receive(:file?).with(test_json_env_val) { false }
         | 
| 184 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 185 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { test_json_env_val }
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                  mocked_signet = mock_signet
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 190 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 191 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 192 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 193 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 194 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 195 | 
            +
                    expect(options[:json_key_io].read).to eq(test_json_env_val)
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 198 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 199 | 
            +
                    default_keyfile_hash
         | 
| 200 | 
            +
                  end
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                  creds = TestCredentials3.default
         | 
| 203 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials3)
         | 
| 204 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 205 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 206 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                it "subclasses can use DEFAULT_PATHS to get keyfile path" do
         | 
| 210 | 
            +
                  class TestCredentials4 < Google::Auth::Credentials
         | 
| 211 | 
            +
                    SCOPE = "http://example.com/scope".freeze
         | 
| 212 | 
            +
                    PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
         | 
| 213 | 
            +
                    JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
         | 
| 214 | 
            +
                    DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                  json_content = JSON.generate default_keyfile_hash
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 220 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 221 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 222 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 223 | 
            +
                  allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
         | 
| 224 | 
            +
                  allow(::File).to receive(:read).with("~/default/path/to/file.txt") { json_content }
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                  mocked_signet = mock_signet
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 229 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 230 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 231 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 232 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 233 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 234 | 
            +
                    expect(options[:json_key_io].read).to eq(json_content)
         | 
| 235 | 
            +
             | 
| 236 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 237 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 238 | 
            +
                    default_keyfile_hash
         | 
| 239 | 
            +
                  end
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                  creds = TestCredentials4.default
         | 
| 242 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials4)
         | 
| 243 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 244 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 245 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 246 | 
            +
                end
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                it "subclasses that find no matches default to Google::Auth.get_application_default" do
         | 
| 249 | 
            +
                  class TestCredentials5 < Google::Auth::Credentials
         | 
| 250 | 
            +
                    SCOPE = "http://example.com/scope".freeze
         | 
| 251 | 
            +
                    PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
         | 
| 252 | 
            +
                    JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
         | 
| 253 | 
            +
                    DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
         | 
| 254 | 
            +
                  end
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 257 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 258 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 259 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 260 | 
            +
                  allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
         | 
| 261 | 
            +
             | 
| 262 | 
            +
                  mocked_signet = mock_signet
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                  allow(Google::Auth).to receive(:get_application_default) do |scope, options|
         | 
| 265 | 
            +
                    expect(scope).to eq([TestCredentials5::SCOPE])
         | 
| 266 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 267 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 268 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 271 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 272 | 
            +
                    default_keyfile_hash
         | 
| 273 | 
            +
                  end
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                  creds = TestCredentials5.default
         | 
| 276 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials5)
         | 
| 277 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 278 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 279 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 280 | 
            +
                end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                it "can be subclassed to pass in other env paths" do
         | 
| 283 | 
            +
                  class TestCredentials6 < Google::Auth::Credentials
         | 
| 284 | 
            +
                    TOKEN_CREDENTIAL_URI = "https://example.com/token".freeze
         | 
| 285 | 
            +
                    AUDIENCE = "https://example.com/audience".freeze
         | 
| 286 | 
            +
                    SCOPE = "http://example.com/scope".freeze
         | 
| 287 | 
            +
                    PATH_ENV_VARS = ["TEST_PATH"].freeze
         | 
| 288 | 
            +
                    JSON_ENV_VARS = ["TEST_JSON_VARS"].freeze
         | 
| 289 | 
            +
                    DEFAULT_PATHS = ["~/default/path/to/file.txt"]
         | 
| 290 | 
            +
                  end
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                  class TestCredentials7 < TestCredentials6
         | 
| 293 | 
            +
                  end
         | 
| 294 | 
            +
             | 
| 295 | 
            +
                  expect(TestCredentials7.token_credential_uri).to eq("https://example.com/token")
         | 
| 296 | 
            +
                  expect(TestCredentials7.audience).to eq("https://example.com/audience")
         | 
| 297 | 
            +
                  expect(TestCredentials7.scope).to eq(["http://example.com/scope"])
         | 
| 298 | 
            +
                  expect(TestCredentials7.env_vars).to eq(["TEST_PATH", "TEST_JSON_VARS"])
         | 
| 299 | 
            +
                  expect(TestCredentials7.paths).to eq(["~/default/path/to/file.txt"])
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                  TestCredentials7::TOKEN_CREDENTIAL_URI = "https://example.com/token2"
         | 
| 302 | 
            +
                  expect(TestCredentials7.token_credential_uri).to eq("https://example.com/token2")
         | 
| 303 | 
            +
                  TestCredentials7::AUDIENCE = nil
         | 
| 304 | 
            +
                  expect(TestCredentials7.audience).to eq("https://example.com/audience")
         | 
| 305 | 
            +
                end
         | 
| 306 | 
            +
              end
         | 
| 307 | 
            +
             | 
| 308 | 
            +
              describe "using class methods" do
         | 
| 309 | 
            +
                it "can be subclassed to pass in other env paths" do
         | 
| 310 | 
            +
                  test_path_env_val = "/unknown/path/to/file.txt".freeze
         | 
| 311 | 
            +
                  test_json_env_val = JSON.generate default_keyfile_hash
         | 
| 312 | 
            +
             | 
| 313 | 
            +
                  ENV["TEST_PATH"] = test_path_env_val
         | 
| 314 | 
            +
                  ENV["TEST_JSON_VARS"] = test_json_env_val
         | 
| 315 | 
            +
             | 
| 316 | 
            +
                  class TestCredentials11 < Google::Auth::Credentials
         | 
| 317 | 
            +
                    self.token_credential_uri = "https://example.com/token"
         | 
| 318 | 
            +
                    self.audience = "https://example.com/audience"
         | 
| 319 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 320 | 
            +
                    self.env_vars = ["TEST_PATH", "TEST_JSON_VARS"]
         | 
| 321 | 
            +
                  end
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                  allow(::File).to receive(:file?).with(test_path_env_val) { false }
         | 
| 324 | 
            +
                  allow(::File).to receive(:file?).with(test_json_env_val) { false }
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                  mocked_signet = mock_signet
         | 
| 327 | 
            +
             | 
| 328 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 329 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://example.com/token")
         | 
| 330 | 
            +
                    expect(options[:audience]).to eq("https://example.com/audience")
         | 
| 331 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 332 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 333 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 334 | 
            +
                    expect(options[:json_key_io].read).to eq(test_json_env_val)
         | 
| 335 | 
            +
             | 
| 336 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 337 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 338 | 
            +
                    default_keyfile_hash
         | 
| 339 | 
            +
                  end
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                  creds = TestCredentials11.default
         | 
| 342 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials11)
         | 
| 343 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 344 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 345 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 346 | 
            +
                end
         | 
| 347 | 
            +
             | 
| 348 | 
            +
                it "subclasses can use PATH_ENV_VARS to get keyfile path" do
         | 
| 349 | 
            +
                  class TestCredentials12 < Google::Auth::Credentials
         | 
| 350 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 351 | 
            +
                    self.env_vars = %w[PATH_ENV_DUMMY PATH_ENV_TEST JSON_ENV_DUMMY]
         | 
| 352 | 
            +
                    self.paths = ["~/default/path/to/file.txt"]
         | 
| 353 | 
            +
                  end
         | 
| 354 | 
            +
             | 
| 355 | 
            +
                  json_content = JSON.generate default_keyfile_hash
         | 
| 356 | 
            +
             | 
| 357 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 358 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 359 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 360 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
         | 
| 361 | 
            +
                  allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
         | 
| 362 | 
            +
                  allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { json_content }
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                  mocked_signet = mock_signet
         | 
| 365 | 
            +
             | 
| 366 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 367 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 368 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 369 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 370 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 371 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 372 | 
            +
                    expect(options[:json_key_io].read).to eq(json_content)
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 375 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 376 | 
            +
                    default_keyfile_hash
         | 
| 377 | 
            +
                  end
         | 
| 378 | 
            +
             | 
| 379 | 
            +
                  creds = TestCredentials12.default
         | 
| 380 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials12)
         | 
| 381 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 382 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 383 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 384 | 
            +
                end
         | 
| 385 | 
            +
             | 
| 386 | 
            +
                it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
         | 
| 387 | 
            +
                  test_json_env_val = JSON.generate default_keyfile_hash
         | 
| 388 | 
            +
             | 
| 389 | 
            +
                  class TestCredentials13 < Google::Auth::Credentials
         | 
| 390 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 391 | 
            +
                    self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY JSON_ENV_TEST]
         | 
| 392 | 
            +
                    self.paths = ["~/default/path/to/file.txt"]
         | 
| 393 | 
            +
                  end
         | 
| 394 | 
            +
             | 
| 395 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 396 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 397 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 398 | 
            +
                  allow(::File).to receive(:file?).with(test_json_env_val) { false }
         | 
| 399 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 400 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { test_json_env_val }
         | 
| 401 | 
            +
             | 
| 402 | 
            +
                  mocked_signet = mock_signet
         | 
| 403 | 
            +
             | 
| 404 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 405 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 406 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 407 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 408 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 409 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 410 | 
            +
                    expect(options[:json_key_io].read).to eq(test_json_env_val)
         | 
| 411 | 
            +
             | 
| 412 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 413 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 414 | 
            +
                    default_keyfile_hash
         | 
| 415 | 
            +
                  end
         | 
| 416 | 
            +
             | 
| 417 | 
            +
                  creds = TestCredentials13.default
         | 
| 418 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials13)
         | 
| 419 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 420 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 421 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 422 | 
            +
                end
         | 
| 423 | 
            +
             | 
| 424 | 
            +
                it "subclasses can use DEFAULT_PATHS to get keyfile path" do
         | 
| 425 | 
            +
                  class TestCredentials14 < Google::Auth::Credentials
         | 
| 426 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 427 | 
            +
                    self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
         | 
| 428 | 
            +
                    self.paths = ["~/default/path/to/file.txt"]
         | 
| 429 | 
            +
                  end
         | 
| 430 | 
            +
             | 
| 431 | 
            +
                  json_content = JSON.generate default_keyfile_hash
         | 
| 432 | 
            +
             | 
| 433 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 434 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 435 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 436 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 437 | 
            +
                  allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
         | 
| 438 | 
            +
                  allow(::File).to receive(:read).with("~/default/path/to/file.txt") { json_content }
         | 
| 439 | 
            +
             | 
| 440 | 
            +
                  mocked_signet = mock_signet
         | 
| 441 | 
            +
             | 
| 442 | 
            +
                  allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds) do |options|
         | 
| 443 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 444 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 445 | 
            +
                    expect(options[:scope]).to eq(["http://example.com/scope"])
         | 
| 446 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 447 | 
            +
                    expect(options[:target_audience]).to be_nil
         | 
| 448 | 
            +
                    expect(options[:json_key_io].read).to eq(json_content)
         | 
| 449 | 
            +
             | 
| 450 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 451 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 452 | 
            +
                    default_keyfile_hash
         | 
| 453 | 
            +
                  end
         | 
| 454 | 
            +
             | 
| 455 | 
            +
                  creds = TestCredentials14.default
         | 
| 456 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials14)
         | 
| 457 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 458 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 459 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 460 | 
            +
                end
         | 
| 461 | 
            +
             | 
| 462 | 
            +
                it "subclasses that find no matches default to Google::Auth.get_application_default with self-signed jwt enabled" do
         | 
| 463 | 
            +
                  class TestCredentials15 < Google::Auth::Credentials
         | 
| 464 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 465 | 
            +
                    self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
         | 
| 466 | 
            +
                    self.paths = ["~/default/path/to/file.txt"]
         | 
| 467 | 
            +
                  end
         | 
| 468 | 
            +
             | 
| 469 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 470 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 471 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 472 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 473 | 
            +
                  allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
         | 
| 474 | 
            +
             | 
| 475 | 
            +
                  mocked_signet = mock_signet
         | 
| 476 | 
            +
             | 
| 477 | 
            +
                  allow(Google::Auth).to receive(:get_application_default) do |scope, options|
         | 
| 478 | 
            +
                    expect(scope).to eq(TestCredentials15.scope)
         | 
| 479 | 
            +
                    expect(options[:enable_self_signed_jwt]).to eq(true)
         | 
| 480 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 481 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 482 | 
            +
             | 
| 483 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 484 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 485 | 
            +
                    default_keyfile_hash
         | 
| 486 | 
            +
                  end
         | 
| 487 | 
            +
             | 
| 488 | 
            +
                  creds = TestCredentials15.default enable_self_signed_jwt: true
         | 
| 489 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials15)
         | 
| 490 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 491 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 492 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 493 | 
            +
                end
         | 
| 494 | 
            +
             | 
| 495 | 
            +
                it "subclasses that find no matches default to Google::Auth.get_application_default with self-signed jwt disabled" do
         | 
| 496 | 
            +
                  class TestCredentials16 < Google::Auth::Credentials
         | 
| 497 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 498 | 
            +
                    self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
         | 
| 499 | 
            +
                    self.paths = ["~/default/path/to/file.txt"]
         | 
| 500 | 
            +
                  end
         | 
| 501 | 
            +
             | 
| 502 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 503 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 504 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 505 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 506 | 
            +
                  allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
         | 
| 507 | 
            +
             | 
| 508 | 
            +
                  mocked_signet = mock_signet
         | 
| 509 | 
            +
             | 
| 510 | 
            +
                  allow(Google::Auth).to receive(:get_application_default) do |scope, options|
         | 
| 511 | 
            +
                    expect(scope).to eq(TestCredentials16.scope)
         | 
| 512 | 
            +
                    expect(options[:enable_self_signed_jwt]).to be_nil
         | 
| 513 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
         | 
| 514 | 
            +
                    expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
         | 
| 515 | 
            +
             | 
| 516 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 517 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 518 | 
            +
                    default_keyfile_hash
         | 
| 519 | 
            +
                  end
         | 
| 520 | 
            +
             | 
| 521 | 
            +
                  creds = TestCredentials16.default
         | 
| 522 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials16)
         | 
| 523 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 524 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 525 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 526 | 
            +
                end
         | 
| 527 | 
            +
             | 
| 528 | 
            +
                it "subclasses that find no matches default to Google::Auth.get_application_default with custom values" do
         | 
| 529 | 
            +
                  scope2 = "http://example.com/scope2"
         | 
| 530 | 
            +
             | 
| 531 | 
            +
                  class TestCredentials17 < Google::Auth::Credentials
         | 
| 532 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 533 | 
            +
                    self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
         | 
| 534 | 
            +
                    self.paths = ["~/default/path/to/file.txt"]
         | 
| 535 | 
            +
                    self.token_credential_uri = "https://example.com/token2"
         | 
| 536 | 
            +
                    self.audience = "https://example.com/token3"
         | 
| 537 | 
            +
                  end
         | 
| 538 | 
            +
             | 
| 539 | 
            +
                  allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
         | 
| 540 | 
            +
                  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
         | 
| 541 | 
            +
                  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
         | 
| 542 | 
            +
                  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
         | 
| 543 | 
            +
                  allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
         | 
| 544 | 
            +
             | 
| 545 | 
            +
                  mocked_signet = mock_signet
         | 
| 546 | 
            +
             | 
| 547 | 
            +
                  allow(Google::Auth).to receive(:get_application_default) do |scope, options|
         | 
| 548 | 
            +
                    expect(scope).to eq(scope2)
         | 
| 549 | 
            +
                    expect(options[:enable_self_signed_jwt]).to eq(false)
         | 
| 550 | 
            +
                    expect(options[:token_credential_uri]).to eq("https://example.com/token2")
         | 
| 551 | 
            +
                    expect(options[:audience]).to eq("https://example.com/token3")
         | 
| 552 | 
            +
             | 
| 553 | 
            +
                    # This should really be a Signet::OAuth2::Client object,
         | 
| 554 | 
            +
                    # but mocking is making that difficult, so return a valid hash instead.
         | 
| 555 | 
            +
                    default_keyfile_hash
         | 
| 556 | 
            +
                  end
         | 
| 557 | 
            +
             | 
| 558 | 
            +
                  creds = TestCredentials17.default scope: scope2, enable_self_signed_jwt: true
         | 
| 559 | 
            +
                  expect(creds).to be_a_kind_of(TestCredentials17)
         | 
| 560 | 
            +
                  expect(creds.client).to eq(mocked_signet)
         | 
| 561 | 
            +
                  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
         | 
| 562 | 
            +
                  expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
         | 
| 563 | 
            +
                end
         | 
| 564 | 
            +
             | 
| 565 | 
            +
                it "subclasses delegate up the class hierarchy" do
         | 
| 566 | 
            +
                  class TestCredentials18 < Google::Auth::Credentials
         | 
| 567 | 
            +
                    self.scope = "http://example.com/scope"
         | 
| 568 | 
            +
                    self.target_audience = "https://example.com/target_audience"
         | 
| 569 | 
            +
                    self.env_vars = ["TEST_PATH", "TEST_JSON_VARS"]
         | 
| 570 | 
            +
                    self.paths = ["~/default/path/to/file.txt"]
         | 
| 571 | 
            +
                  end
         | 
| 572 | 
            +
             | 
| 573 | 
            +
                  class TestCredentials19 < TestCredentials18
         | 
| 574 | 
            +
                  end
         | 
| 575 | 
            +
             | 
| 576 | 
            +
                  expect(TestCredentials19.scope).to eq(["http://example.com/scope"])
         | 
| 577 | 
            +
                  expect(TestCredentials19.target_audience).to eq("https://example.com/target_audience")
         | 
| 578 | 
            +
                  expect(TestCredentials19.env_vars).to eq(["TEST_PATH", "TEST_JSON_VARS"])
         | 
| 579 | 
            +
                  expect(TestCredentials19.paths).to eq(["~/default/path/to/file.txt"])
         | 
| 580 | 
            +
             | 
| 581 | 
            +
                  TestCredentials19.token_credential_uri = "https://example.com/token2"
         | 
| 582 | 
            +
                  expect(TestCredentials19.token_credential_uri).to eq("https://example.com/token2")
         | 
| 583 | 
            +
                  TestCredentials19.token_credential_uri = nil
         | 
| 584 | 
            +
                  expect(TestCredentials19.token_credential_uri).to eq("https://oauth2.googleapis.com/token")
         | 
| 585 | 
            +
                end
         | 
| 586 | 
            +
              end
         | 
| 587 | 
            +
             | 
| 588 | 
            +
              it "warns when cloud sdk credentials are used" do
         | 
| 589 | 
            +
                mocked_signet = double "Signet::OAuth2::Client"
         | 
| 590 | 
            +
                allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
         | 
| 591 | 
            +
                allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
         | 
| 592 | 
            +
                allow(Signet::OAuth2::Client).to receive(:new) do |_options|
         | 
| 593 | 
            +
                  mocked_signet
         | 
| 594 | 
            +
                end
         | 
| 595 | 
            +
                allow(mocked_signet).to receive(:client_id).and_return(Google::Auth::CredentialsLoader::CLOUD_SDK_CLIENT_ID)
         | 
| 596 | 
            +
                expect { Google::Auth::Credentials.new default_keyfile_hash }.to output(
         | 
| 597 | 
            +
                  Google::Auth::CredentialsLoader::CLOUD_SDK_CREDENTIALS_WARNING + "\n"
         | 
| 598 | 
            +
                ).to_stderr
         | 
| 599 | 
            +
              end
         | 
| 600 | 
            +
            end
         |