| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | using Google.Apis.Tests.Mocks; |
| | using Google.Apis.Util; |
| | using Newtonsoft.Json; |
| | using System; |
| | using System.Linq; |
| | using System.Threading.Tasks; |
| | using Xunit; |
| | using static Google.Apis.Auth.TokenEncodingHelpers; |
| |
|
| | namespace Google.Apis.Auth.Tests |
| | { |
| | public class JsonWebSignatureTests |
| | { |
| | private SignedTokenVerificationOptions BuildOptions( |
| | IClock clock = null, string[] trustedIssuers = null, string[] trustedAudiences = null, TimeSpan? clockTolerance = null) |
| | { |
| | var options = new SignedTokenVerificationOptions |
| | { |
| | CertificateCache = new FakeCertificateCache(), |
| | Clock = clock ?? new MockClock(FakeCertificateCache.ValidJwtGoogleSigned) |
| | }; |
| | foreach (var issuer in trustedIssuers ?? Enumerable.Empty<string>()) |
| | { |
| | options.TrustedIssuers.Add(issuer); |
| | } |
| | foreach (var audience in trustedAudiences ?? Enumerable.Empty<string>()) |
| | { |
| | options.TrustedAudiences.Add(audience); |
| | } |
| | if (clockTolerance.HasValue) |
| | { |
| | options.IssuedAtClockTolerance = clockTolerance.Value; |
| | options.ExpiryClockTolerance = clockTolerance.Value; |
| | } |
| |
|
| | return options; |
| | } |
| |
|
| | [Fact] |
| | public async Task NullToken() => |
| | await Assert.ThrowsAsync<ArgumentNullException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(null, BuildOptions())); |
| |
|
| | [Fact] |
| | public async Task EmptyToken() => |
| | await Assert.ThrowsAsync<ArgumentException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync("", BuildOptions())); |
| |
|
| | [Fact] |
| | public async Task TwoPartToken() => |
| | await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync("header.payload", BuildOptions())); |
| |
|
| | [Fact] |
| | public async Task WrongAlgorithm() |
| | { |
| | string jwt = $"{UrlSafeBase64Encode("{\"alg\":\"HS256\"}")}.{UrlSafeBase64Encode("{}")}."; |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(jwt, BuildOptions())); |
| | Assert.Equal("Signing algorithm must be either RS256 or ES256.", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task ValidRS256Signature() => |
| | Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync( |
| | FakeCertificateCache.JwtGoogleSigned, BuildOptions())); |
| |
|
| | [Fact] |
| | public async Task ValidRS256Signature_CustomPayload() |
| | { |
| | var payload = await JsonWebSignature.VerifySignedTokenAsync<CustomPayload>(FakeCertificateCache.JwtGoogleSigned, BuildOptions()); |
| | Assert.NotNull(payload); |
| | Assert.NotNull(payload.AuthorizedParty); |
| | Assert.NotEmpty(payload.AuthorizedParty); |
| | } |
| |
|
| | private class CustomPayload : JsonWebSignature.Payload |
| | { |
| | [JsonProperty("azp")] |
| | public string AuthorizedParty { get; set; } |
| | } |
| |
|
| | [Fact] |
| | public async Task ValidES256Signature() => |
| | Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync( |
| | FakeCertificateCache.Es256ForIap, BuildOptions(new MockClock(FakeCertificateCache.ValidEs256ForIap)))); |
| |
|
| | [Fact] |
| | public async Task InvalidRS256Signature() |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | var invalidToken = FakeCertificateCache.JwtGoogleSigned.Substring(0, FakeCertificateCache.JwtGoogleSigned.Length - 1) + "4"; |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(invalidToken, BuildOptions())); |
| | Assert.Equal("JWT invalid, unable to verify signature.", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task InvalidES256Signature() |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | var invalidToken = FakeCertificateCache.Es256ForIap.Substring(0, FakeCertificateCache.Es256ForIap.Length - 1) + "4"; |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(invalidToken, BuildOptions(new MockClock(FakeCertificateCache.ValidEs256ForIap)))); |
| | Assert.Equal("JWT invalid, unable to verify signature.", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task InvalidIssuer() |
| | { |
| | var options = BuildOptions(trustedIssuers: new string[] { "issuer1", "issuer2" }); |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, options)); |
| | Assert.Equal("JWT issuer incorrect. Must be one of: 'issuer1', 'issuer2'", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task InvalidAudience() |
| | { |
| | var options = BuildOptions(trustedAudiences: new string[] { "audience1", "audience2" }); |
| | var ex = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, options)); |
| | Assert.Equal("JWT contains untrusted 'aud' claim.", ex.Message); |
| | } |
| |
|
| | [Fact] |
| | public async Task ValidAudience() |
| | { |
| | var options = BuildOptions(trustedAudiences: new string[] { "233772281425-ab2mcbiqmv8kh0mdnqsrkrod97qk37h0.apps.googleusercontent.com" }); |
| | var payload = await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, options); |
| | Assert.NotNull(payload); |
| | } |
| |
|
| | [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 JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockValid1))); |
| |
|
| | var ex1 = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1))); |
| | Assert.Equal("JWT is not yet valid.", ex1.Message); |
| |
|
| | var ex2 = await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2))); |
| | Assert.Equal("JWT has expired.", ex2.Message); |
| |
|
| | |
| | await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1, clockTolerance: TimeSpan.FromSeconds(109)))); |
| | Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1, clockTolerance: TimeSpan.FromSeconds(111)))); |
| | Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2, clockTolerance: TimeSpan.FromSeconds(11)))); |
| | await Assert.ThrowsAsync<InvalidJwtException>(() => |
| | JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2, clockTolerance: TimeSpan.FromSeconds(9)))); |
| | } |
| | } |
| | } |
| |
|