Skip to content

Commit

Permalink
Merge branch 'main' into feature/typed-errors
Browse files Browse the repository at this point in the history
  • Loading branch information
dazuma authored Oct 4, 2024
2 parents f423618 + a254aa2 commit 3978aa2
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 25 deletions.
8 changes: 4 additions & 4 deletions .github/sync-repo-settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ branchProtectionRules:
isAdminEnforced: false
requiredStatusCheckContexts:
- 'cla/google'
- 'CI (macos-latest, 3.2, test , spec)'
- 'CI (ubuntu-20.04, 2.7, test , spec)'
- 'CI (macos-latest, 3.3, test , spec)'
- 'CI (ubuntu-20.04, 3.0, test , spec)'
- 'CI (ubuntu-20.04, 3.1, test , spec)'
- 'CI (ubuntu-22.04, 3.2, test , spec)'
- 'CI (ubuntu-latest, 3.2, rubocop , integration , build , yardoc , linkinator)'
- 'CI (windows-latest, 3.2, test , spec)'
- 'CI (ubuntu-latest, 3.3, rubocop , integration , build , yardoc , linkinator)'
- 'CI (ubuntu-latest, 3.3, test , spec)'
- 'CI (windows-latest, 3.3, test , spec)'
requiredApprovingReviewCount: 1
requiresCodeOwnerReviews: true
requiresStrictStatusChecks: true
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ jobs:
strategy:
matrix:
include:
- os: ubuntu-20.04
ruby: "2.7"
task: test , spec
- os: ubuntu-20.04
ruby: "3.0"
task: test , spec
Expand All @@ -25,14 +22,17 @@ jobs:
- os: ubuntu-22.04
ruby: "3.2"
task: test , spec
- os: ubuntu-latest
ruby: "3.3"
task: test , spec
- os: macos-latest
ruby: "3.2"
ruby: "3.3"
task: test , spec
- os: windows-latest
ruby: "3.2"
ruby: "3.3"
task: test , spec
- os: ubuntu-latest
ruby: "3.2"
ruby: "3.3"
task: rubocop , integration , build , yardoc , linkinator
fail-fast: false
runs-on: ${{ matrix.os }}
Expand Down
11 changes: 10 additions & 1 deletion lib/googleauth/compute_engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def fetch_access_token _options = {}
def build_token_hash body, content_type, retrieval_time
hash =
if ["text/html", "application/text"].include? content_type
{ token_type.to_s => body }
parse_encoded_token body
else
Signet::OAuth2.parse_credentials body, content_type
end
Expand All @@ -143,6 +143,15 @@ def build_token_hash body, content_type, retrieval_time
end
hash
end

def parse_encoded_token body
hash = { token_type.to_s => body }
if token_type == :id_token
expires_at = expires_at_from_id_token body
hash["expires_at"] = expires_at if expires_at
end
hash
end
end
end
end
17 changes: 17 additions & 0 deletions lib/googleauth/signet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

require "base64"
require "json"
require "signet/oauth_2/client"
require "googleauth/base_client"

Expand All @@ -29,6 +31,8 @@ class Client

def update_token! options = {}
options = deep_hash_normalize options
id_token_expires_at = expires_at_from_id_token options[:id_token]
options[:expires_at] = id_token_expires_at if id_token_expires_at
update_token_signet_base options
self.universe_domain = options[:universe_domain] if options.key? :universe_domain
self
Expand Down Expand Up @@ -89,6 +93,19 @@ def retry_with_error max_retry_count = 5
end
end
end

private

def expires_at_from_id_token id_token
match = /^[\w=-]+\.([\w=-]+)\.[\w=-]+$/.match id_token.to_s
return unless match
json = JSON.parse Base64.urlsafe_decode64 match[1]
return unless json.key? "exp"
Time.at json["exp"].to_i
rescue StandardError
# Shouldn't happen unless we get a garbled ID token
nil
end
end
end
end
45 changes: 34 additions & 11 deletions spec/googleauth/compute_engine_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def make_auth_stubs opts
expiry = @client.expires_at
sleep 1
@client.fetch_access_token!
expect(@client.expires_at.to_f).to be_within(0.1).of(expiry.to_f)
expect(@client.expires_at.to_f).to be_within(0.2).of(expiry.to_f)
end
end

Expand All @@ -107,7 +107,7 @@ def make_auth_stubs opts
expiry = @client.expires_at
sleep 1
@client.fetch_access_token!
expect(@client.expires_at.to_f).to be_within(0.1).of(expiry.to_f)
expect(@client.expires_at.to_f).to be_within(0.2).of(expiry.to_f)
end
end

Expand Down Expand Up @@ -152,16 +152,46 @@ def make_auth_stubs opts
end
end

context "metadata is unavailable" do
context "metadata is available" do
describe "#fetch_access_token" do
it "should pass scopes when requesting an access token" do
it "should pass scopes" do
scopes = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/bigtable.data"]
stub = make_auth_stubs access_token: "1/abcdef1234567890", scope: scopes
@client = GCECredentials.new(scope: scopes)
@client.fetch_access_token!
expect(stub).to have_been_requested
end
end

describe "Fetch ID tokens" do
it "should parse out expiration time" do
expiry_time = 1608886800
header = {
alg: "RS256",
kid: "1234567890123456789012345678901234567890",
typ: "JWT"
}
payload = {
aud: "http://www.example.com",
azp: "67890",
email: "googleapis-test@developer.gserviceaccount.com",
email_verified: true,
exp: expiry_time,
iat: expiry_time - 3600,
iss: "https://accounts.google.com",
sub: "12345"
}
token = "#{Base64.urlsafe_encode64 JSON.dump header}.#{Base64.urlsafe_encode64 JSON.dump payload}.xxxxx"
stub = make_auth_stubs id_token: token
@id_client.fetch_access_token!
expect(stub).to have_been_requested
expect(@id_client.expires_at.to_i).to eq(expiry_time)
end
end
end

context "metadata is unavailable" do
describe "#fetch_access_token" do
it "should fail if the metadata request returns a 404" do
stub = stub_request(:get, MD_ACCESS_URI)
.to_return(status: 404,
Expand Down Expand Up @@ -214,13 +244,6 @@ def make_auth_stubs opts
end

describe "Fetch ID tokens" do
it "should pass scopes when requesting an ID token" do
scopes = ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/bigtable.data"]
stub = make_auth_stubs id_token: "1/abcdef1234567890", scope: scopes
@id_client.fetch_access_token!
expect(stub).to have_been_requested
end

it "should fail if the metadata request returns a 404" do
stub = stub_request(:get, MD_ID_URI)
.to_return(status: 404,
Expand Down
38 changes: 35 additions & 3 deletions spec/googleauth/service_account_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,14 @@ def expect_is_encoded_jwt hdr
end

def make_auth_stubs opts
body_fields = { "token_type" => "Bearer", "expires_in" => 3600 }
body_fields["access_token"] = opts[:access_token] if opts[:access_token]
body_fields["id_token"] = opts[:id_token] if opts[:id_token]
body_fields =
if opts[:access_token]
{ "access_token" => opts[:access_token], "token_type" => "Bearer", "expires_in" => 3600 }
elsif opts[:id_token]
{ "id_token" => opts[:id_token] }
else
raise "Expected access_token or id_token"
end
body = MultiJson.dump body_fields
blk = proc do |request|
params = Addressable::URI.form_unencode request.body
Expand Down Expand Up @@ -217,6 +222,33 @@ def cred_json_text_with_universe_domain
it_behaves_like "jwt header auth", nil
end

context "when target_audience is set" do
it "retrieves an ID token with expiration" do
expiry_time = 1608886800
header = {
alg: "RS256",
kid: "1234567890123456789012345678901234567890",
typ: "JWT"
}
payload = {
aud: "http://www.example.com",
azp: "67890",
email: "googleapis-test@developer.gserviceaccount.com",
email_verified: true,
exp: expiry_time,
iat: expiry_time - 3600,
iss: "https://accounts.google.com",
sub: "12345"
}
id_token = "#{Base64.urlsafe_encode64 JSON.dump header}.#{Base64.urlsafe_encode64 JSON.dump payload}.xxxxx"
stub = make_auth_stubs id_token: id_token
@id_client.fetch_access_token!
expect(stub).to have_been_requested
expect(@id_client.id_token).to eq(id_token)
expect(@id_client.expires_at.to_i).to eq(expiry_time)
end
end

describe "#from_env" do
before :example do
@var_name = ENV_VAR
Expand Down

0 comments on commit 3978aa2

Please sign in to comment.