| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | using Google.Apis.Auth.OAuth2; |
| | using Google.Apis.Tests.Mocks; |
| | using Google.Apis.Util; |
| | using System; |
| | using System.Linq; |
| | using System.Threading.Tasks; |
| | using Xunit; |
| | using static Google.Apis.Auth.SignedTokenVerification; |
| | using static Google.Apis.Auth.TokenEncodingHelpers; |
| |
|
| | namespace Google.Apis.Auth.Tests |
| | { |
| | public class GoogleJsonWebSignatureTests |
| | { |
| | private GoogleJsonWebSignature.ValidationSettings MakeSettings( |
| | IClock clock, |
| | string aud = null, |
| | string hd = null, |
| | double clockToleranceSeconds = 0.0, |
| | CertificateCacheBase certificateCache = null) => |
| | new GoogleJsonWebSignature.ValidationSettings |
| | { |
| | Clock = clock, |
| | Audience = aud == null ? null : new[] { aud }, |
| | HostedDomain = hd, |
| | IssuedAtClockTolerance = TimeSpan.FromSeconds(clockToleranceSeconds), |
| | ExpirationTimeClockTolerance = TimeSpan.FromSeconds(clockToleranceSeconds), |
| | CertificateCache = certificateCache ?? new FakeCertificateCache() |
| | }; |
| |
|
| | [Fact] |
| | public void ValidationSettingsToSignedTokenVerificationOptions() |
| | { |
| | MockClock clock = new MockClock(DateTime.UtcNow); |
| | FakeCertificateCache cache = new FakeCertificateCache(); |
| | var options = new GoogleJsonWebSignature.ValidationSettings |
| | { |
| | Clock = clock, |
| | Audience = new[] { "audience" }, |
| | HostedDomain = "hosted_domain", |
| | IssuedAtClockTolerance = TimeSpan.FromSeconds(5), |
| | ExpirationTimeClockTolerance = TimeSpan.FromSeconds(10), |
| | CertificateCache = cache, |
| | ForceGoogleCertRefresh = true |
| | }.ToVerificationOptions(); |
| |
|
| | Assert.Same(clock, options.Clock); |
| | Assert.Single(options.TrustedAudiences, "audience"); |
| | Assert.Equal(TimeSpan.FromSeconds(5), options.IssuedAtClockTolerance); |
| | Assert.Equal(TimeSpan.FromSeconds(10), options.ExpiryClockTolerance); |
| | Assert.Same(cache, options.CertificateCache); |
| | Assert.True(options.ForceCertificateRefresh); |
| | Assert.Equal(GoogleAuthConsts.JsonWebKeySetUrl, options.CertificatesUrl); |
| | Assert.Equal(GoogleJsonWebSignature.ValidJwtIssuers.Count(), options.TrustedIssuers.Count); |
| | } |
| |
|
| | [Fact] |
| | public async Task Validate_BadJwt() |
| | { |
| | |
| | |
| | var settings = MakeSettings(new MockClock(FakeCertificateCache.ValidJwtGoogleSigned)); |
| | |
| | await Assert.ThrowsAsync<ArgumentNullException>(() => GoogleJsonWebSignature.ValidateInternalAsync(null, settings)); |
| | |
| | await Assert.ThrowsAsync<ArgumentException>(() => GoogleJsonWebSignature.ValidateInternalAsync("", settings)); |
| | |
| | await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(new string('a', GoogleJsonWebSignature.MaxJwtLength + 1), settings)); |
| | |
| | await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync("header.payload", settings)); |
| | } |
| |
|
| | [Fact] |
| | public async Task WrongAlgorithm() |
| | { |
| | var settings = MakeSettings(new MockClock(DateTime.UtcNow)); |
| | string jwt = $"{UrlSafeBase64Encode("{\"alg\":\"HS256\"}")}.{UrlSafeBase64Encode("{}")}."; |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(jwt, settings)); |
| | Assert.Equal("JWT algorithm must be 'RS256'", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task ValidateInternalAsync_Valid() |
| | { |
| | var clockValid = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned); |
| | Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockValid))); |
| | } |
| |
|
| | [Fact] |
| | public async Task ValidateInternalAsync_Invalid() |
| | { |
| | var clockValid = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned); |
| | |
| | |
| | |
| | |
| | |
| | |
| | var invalidToken = FakeCertificateCache.JwtGoogleSigned.Substring(0, FakeCertificateCache.JwtGoogleSigned.Length - 1) + "4"; |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(invalidToken, MakeSettings(clockValid))); |
| | Assert.Equal("JWT invalid, unable to verify signature.", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task Invalid_Iss() |
| | { |
| | var clock = new MockClock(FakeCertificateCache.ValidJwtNonGoogleSigned); |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtNonGoogleSigned, MakeSettings(clock))); |
| | Assert.Equal("JWT issuer incorrect. Must be one of: 'https://accounts.google.com', 'accounts.google.com'", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task Invalid_Aud() |
| | { |
| | var clock = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned); |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clock, "bad_aud"))); |
| | Assert.Equal("JWT contains untrusted 'aud' claim.", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task Validate_Signature_Time() |
| | { |
| | var clockInvalid1 = new MockClock(FakeCertificateCache.BeforeValidJwtGoogleSigned); |
| | var clockValid1 = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned); |
| | var clockInvalid2 = new MockClock(FakeCertificateCache.AfterValidJwtGoogleSigned); |
| |
|
| | |
| | Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockValid1))); |
| |
|
| | var ex1 = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid1))); |
| | Assert.Equal("JWT is not yet valid.", ex1.Message); |
| |
|
| | var ex2 = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid2))); |
| | Assert.Equal("JWT has expired.", ex2.Message); |
| |
|
| | |
| | await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid1, clockToleranceSeconds: 109))); |
| | Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid1, clockToleranceSeconds: 111))); |
| | Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid2, clockToleranceSeconds: 11))); |
| | await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid2, clockToleranceSeconds: 9))); |
| | } |
| |
|
| | [Fact] |
| | public async Task Invalid_HostedDomain() |
| | { |
| | var clock = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned); |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clock, hd: "hd"))); |
| | Assert.Equal("JWT contains invalid 'hd' claim.", ex.Message); |
| | } |
| | } |
| | } |
| |
|