Example #1
0
        public void FromNonGoogleSigned()
        {
            var signedToken = SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(FakeCertificateCache.JwtNonGoogleSigned);

            // Just a small test that everything got correctly unpacked.
            Assert.DoesNotContain("google.com", signedToken.Payload.Issuer);
        }
Example #2
0
        public async Task FetchesOidcToken()
        {
            // A little bit after the tokens returned from OidcTokenFakes were issued.
            var clock          = new MockClock(new DateTime(2020, 5, 13, 15, 0, 0, 0, DateTimeKind.Utc));
            var messageHandler = new OidcTokenResponseSuccessMessageHandler();
            var initializer    = new ServiceAccountCredential.Initializer("MyId", "http://will.be.ignored")
            {
                Clock             = clock,
                ProjectId         = "a_project_id",
                HttpClientFactory = new MockHttpClientFactory(messageHandler)
            };
            var credential = new ServiceAccountCredential(initializer.FromPrivateKey(PrivateKey));

            // The fake Oidc server returns valid tokens (expired in the real world for safety)
            // but with a set audience that lets us know if the token was refreshed or not.
            var oidcToken = await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience("will.be.ignored"));

            var signedToken = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Move the clock some but not enough that the token expires.
            clock.UtcNow = clock.UtcNow.AddMinutes(20);
            signedToken  = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Only the first call should have resulted in a request. The second time the token hadn't expired.
            Assert.Equal(1, messageHandler.Calls);
        }
Example #3
0
        public async Task RefreshesOidcToken()
        {
            // A little bit after the tokens returned from OidcTokenFakes were issued.
            var clock          = new MockClock(new DateTime(2020, 5, 13, 15, 0, 0, 0, DateTimeKind.Utc));
            var messageHandler = new OidcTokenResponseSuccessMessageHandler();
            var initializer    = new ServiceAccountCredential.Initializer("MyId", "http://will.be.ignored")
            {
                Clock             = clock,
                ProjectId         = "a_project_id",
                HttpClientFactory = new MockHttpClientFactory(messageHandler)
            };
            var credential = new ServiceAccountCredential(initializer.FromPrivateKey(PrivateKey));

            var oidcToken = await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience("audience"));

            var signedToken = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Move the clock so that the token expires.
            clock.UtcNow = clock.UtcNow.AddHours(2);
            signedToken  = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://subsequent_calls.test", signedToken.Payload.Audience);
            // Two calls, because the second time we tried to get the token, the first one had expired.
            Assert.Equal(2, messageHandler.Calls);
        }
        public async Task RefreshesOidcToken()
        {
            // A little bit after the tokens returned from OidcTokenFakes were issued.
            var clock          = new MockClock(new DateTime(2020, 5, 21, 9, 20, 0, 0, DateTimeKind.Utc));
            var messageHandler = new OidcComputeSuccessMessageHandler();
            var initializer    = new ComputeCredential.Initializer("http://will.be.ignored", "http://will.be.ignored")
            {
                Clock             = clock,
                HttpClientFactory = new MockHttpClientFactory(messageHandler)
            };
            var credential = new ComputeCredential(initializer);

            // The fake Oidc server returns valid tokens (expired in the real world for safty)
            // but with a set audience that lets us know if the token was refreshed or not.
            var oidcToken = await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience("will.be.ignored"));

            var signedToken = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Move the clock so that the token expires.
            clock.UtcNow = clock.UtcNow.AddHours(2);
            signedToken  = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://subsequent_calls.test", signedToken.Payload.Audience);
            // Two calls, because the second time we tried to get the token, the first one had expired.
            Assert.Equal(2, messageHandler.Calls);
        }
Example #5
0
        public void FromGoogleSigned_ToJsonWebSignatureTypes()
        {
            // This works, we just don't get the specific fields that we can get with
            // GoogleJsonWebSignature.Header and GoogleJsonWebSignature.Payload.
            var signedToken = SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(FakeCertificateCache.JwtGoogleSigned);

            // Just a small test that everything got correctly unpacked.
            Assert.Contains("google.com", signedToken.Payload.Issuer);
        }
Example #6
0
        public void FromGoogleSigned()
        {
            var signedToken = SignedToken <GoogleJsonWebSignature.Header, GoogleJsonWebSignature.Payload> .FromSignedToken(FakeCertificateCache.JwtGoogleSigned);

            // Just a small test that everything got correctly unpacked.
            Assert.Contains("google.com", signedToken.Payload.Issuer);
            // And that we have some Google specific info on the payload.
            Assert.NotNull(signedToken.Payload.HostedDomain);
        }
Example #7
0
 internal virtual void Validate(SignedToken signedToken, RevocationData data)
 {
     if (data == null)
     {
         throw new ArgumentException("data cannot be null");
     }
     if (!revocationInfo.ContainsKey(signedToken))
     {
         throw new ArgumentException(signedToken + " must be a key of revocationInfo");
     }
     revocationInfo.Put(signedToken, data);
 }
Example #8
0
 internal virtual void AddNotYetVerifiedToken(SignedToken signedToken)
 {
     if (!revocationInfo.ContainsKey(signedToken))
     {
         LOG.Info("New token to validate " + signedToken + " hashCode " + signedToken.GetHashCode
                      ());
         revocationInfo.Put(signedToken, null);
         if (signedToken is CRLToken)
         {
             neededCRL.AddItem(((CRLToken)signedToken).GetX509crl());
         }
         else
         {
             if (signedToken is OCSPRespToken)
             {
                 neededOCSPResp.AddItem(((OCSPRespToken)signedToken).GetOcspResp());
             }
             else
             {
                 if (signedToken is CertificateToken)
                 {
                     bool found = false;
                     CertificateAndContext newCert = ((CertificateToken)signedToken).GetCertificateAndContext
                                                         ();
                     foreach (CertificateAndContext c in neededCertificates)
                     {
                         if (c.GetCertificate().Equals(newCert.GetCertificate()))
                         {
                             found = true;
                             break;
                         }
                     }
                     if (!found)
                     {
                         neededCertificates.AddItem(newCert);
                     }
                 }
             }
         }
     }
     else
     {
         LOG.Info("Token was already in list " + signedToken);
     }
 }
Example #9
0
        public void FromNonGoogleSigned_ToGoogleJsonWebSignatureTypes()
        {
            // This works, because JSON deserialization will just leave unassigned
            // any of the Google specific fields since they are not present on the JSON.
            // Validation of this token as a Google signed token won't work though.
            var signedToken = SignedToken <GoogleJsonWebSignature.Header, GoogleJsonWebSignature.Payload> .FromSignedToken(FakeCertificateCache.JwtNonGoogleSigned);

            // Just a small test that everything got correctly unpacked.
            Assert.DoesNotContain("google.com", signedToken.Payload.Issuer);
            // But we don't have info for any of the specific Google fields.
            Assert.Null(signedToken.Payload.Scope);
            Assert.Null(signedToken.Payload.Prn);
            Assert.Null(signedToken.Payload.HostedDomain);
            Assert.Null(signedToken.Payload.Email);
            Assert.Null(signedToken.Payload.Name);
            Assert.Null(signedToken.Payload.GivenName);
            Assert.Null(signedToken.Payload.FamilyName);
            Assert.Null(signedToken.Payload.Picture);
            Assert.Null(signedToken.Payload.Locale);
        }
        public async Task FromComputeCredential_FetchesOidcToken()
        {
            // A little bit after the tokens returned from OidcTokenFakes were issued.
            var clock          = new MockClock(new DateTime(2020, 5, 21, 9, 20, 0, 0, DateTimeKind.Utc));
            var messageHandler = new OidcComputeSuccessMessageHandler();
            var initializer    = new ComputeCredential.Initializer("http://will.be.ignored", "http://will.be.ignored")
            {
                Clock             = clock,
                HttpClientFactory = new MockHttpClientFactory(messageHandler)
            };
            var computeCredential = new ComputeCredential(initializer);
            var googleCredential  = GoogleCredential.FromComputeCredential(computeCredential);

            // The fake Oidc server returns valid tokens (expired in the real world for safty)
            // but with a set audience that lets us know if the token was refreshed or not.
            var oidcToken = await googleCredential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience("will.be.ignored"));

            var signedToken = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
        }
Example #11
0
 public void FromSignedToken_ThrowsIfEmpty()
 {
     Assert.Throws <ArgumentException>(
         () => SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(string.Empty));
 }
Example #12
0
        /// <summary>Build the validation context for the specific date</summary>
        /// <param name="validationDate"></param>
        /// <param name="optionalSource"></param>
        /// <exception cref="System.IO.IOException"></exception>
        public virtual void Validate(DateTime validationDate, CertificateSource optionalSource
                                     , ICrlSource optionalCRLSource, IOcspSource optionalOCPSSource)
        {
            int         previousSize     = revocationInfo.Count;
            int         previousVerified = VerifiedTokenCount();
            SignedToken signedToken      = GetOneNotYetVerifiedToken();

            if (signedToken != null)
            {
                CertificateSource otherSource = optionalSource;
                if (signedToken != null)
                {
                    otherSource = new CompositeCertificateSource(signedToken.GetWrappedCertificateSource
                                                                     (), optionalSource);
                }
                CertificateAndContext issuer = GetIssuerCertificate(signedToken, otherSource, validationDate
                                                                    );
                RevocationData data = null;
                if (issuer == null)
                {
                    LOG.Warn("Don't found any issuer for token " + signedToken);
                    data = new RevocationData(signedToken);
                }
                else
                {
                    AddNotYetVerifiedToken(new CertificateToken(issuer));
                    if (issuer.GetCertificate().SubjectDN.Equals(issuer.GetCertificate
                                                                     ().IssuerDN))
                    {
                        SignedToken    trustedToken     = new CertificateToken(issuer);
                        RevocationData noNeedToValidate = new RevocationData();
                        // noNeedToValidate.setRevocationData(CertificateSourceType.TRUSTED_LIST);
                        Validate(trustedToken, noNeedToValidate);
                    }
                    if (issuer.GetCertificateSource() == CertificateSourceType.TRUSTED_LIST)
                    {
                        SignedToken    trustedToken     = new CertificateToken(issuer);
                        RevocationData noNeedToValidate = new RevocationData();
                        noNeedToValidate.SetRevocationData(CertificateSourceType.TRUSTED_LIST);
                        Validate(trustedToken, noNeedToValidate);
                    }
                    if (signedToken is CertificateToken)
                    {
                        CertificateToken  ct     = (CertificateToken)signedToken;
                        CertificateStatus status = GetCertificateValidity(ct.GetCertificateAndContext(),
                                                                          issuer, validationDate, optionalCRLSource, optionalOCPSSource);
                        data = new RevocationData(signedToken);
                        if (status != null)
                        {
                            data.SetRevocationData(status.StatusSource);
                            if (status.StatusSource is X509Crl)
                            {
                                AddNotYetVerifiedToken(new CRLToken((X509Crl)status.StatusSource));
                            }
                            else
                            {
                                if (status.StatusSource is BasicOcspResp)
                                {
                                    AddNotYetVerifiedToken(new OCSPRespToken((BasicOcspResp)status.StatusSource));
                                }
                            }
                        }
                        else
                        {
                            LOG.Warn("No status for " + signedToken);
                        }
                    }
                    else
                    {
                        if (signedToken is CRLToken || signedToken is OCSPRespToken || signedToken is TimestampToken)
                        {
                            data = new RevocationData(signedToken);
                            data.SetRevocationData(issuer);
                        }
                        else
                        {
                            throw new RuntimeException("Not supported token type " + signedToken.GetType().Name
                                                       );
                        }
                    }
                }
                Validate(signedToken, data);
                LOG.Info(this.ToString());
                int newSize     = revocationInfo.Count;
                int newVerified = VerifiedTokenCount();
                if (newSize != previousSize || newVerified != previousVerified)
                {
                    Validate(validationDate, otherSource, optionalCRLSource, optionalOCPSSource);
                }
            }
        }
Example #13
0
 public void FromSignedToken_ThrowsIfNull()
 {
     Assert.Throws <ArgumentNullException>(
         () => SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(null));
 }
Example #14
0
        /// <summary>
        /// Asynchronously parses a <see cref="TokenResponse"/> instance from the specified <see cref="HttpResponseMessage"/>.
        /// </summary>
        /// <param name="response">The http response from which to parse the token.</param>
        /// <param name="clock">The clock used to set the <see cref="Issued"/> value of the token.</param>
        /// <param name="logger">The logger used to output messages incase of error.</param>
        /// <exception cref="TokenResponseException">
        /// The response was not successful or there is an error parsing the response into valid <see cref="TokenResponse"/> instance.
        /// </exception>
        /// <returns>
        /// A task containing the <see cref="TokenResponse"/> parsed form the response message.
        /// </returns>
        public static async Task <TokenResponse> FromHttpResponseAsync(HttpResponseMessage response, IClock clock, ILogger logger)
        {
            var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

            var typeName = "";

            try
            {
                if (!response.IsSuccessStatusCode)
                {
                    typeName = nameof(TokenErrorResponse);
                    var error = NewtonsoftJsonSerializer.Instance.Deserialize <TokenErrorResponse>(content);
                    throw new TokenResponseException(error, response.StatusCode);
                }

                TokenResponse newToken;
                // GCE's metadata server identity endpoint doesn't return a TokenResponse but the raw
                // id_token, so we build a TokenResponse from that.
                if (response.RequestMessage?.RequestUri?.AbsoluteUri.StartsWith(GoogleAuthConsts.ComputeOidcTokenUrl) == true)
                {
                    newToken = new TokenResponse
                    {
                        IdToken = content
                    };
                }
                else
                {
                    typeName = nameof(TokenResponse);
                    newToken = NewtonsoftJsonSerializer.Instance.Deserialize <TokenResponse>(content);
                }
                // We make some modifications to the token before returning, to guarantee consistency
                // for our code across endpoint usage.

                // We should set issuance ourselves.
                newToken.IssuedUtc = clock.UtcNow;
                // If no access token was specified, then we're probably receiving
                // and OIDC token for IAP. The IdToken is used for access in that case.
                newToken.AccessToken ??= newToken.IdToken;

                // If no expiry is specified, maybe the IdToken has it specified.
                // We can try and get it from there.
                if (newToken.ExpiresInSeconds is null && newToken.IdToken != null)
                {
                    // Unpack the IdToken.
                    var idToken = SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(newToken.IdToken);

                    // If no expiry was specified in the ID token, there's nothing we can do.
                    if (idToken.Payload.ExpirationTimeSeconds.HasValue)
                    {
                        var expiration = UnixEpoch.AddSeconds(idToken.Payload.ExpirationTimeSeconds.Value);
                        newToken.ExpiresInSeconds = (long)(expiration - newToken.IssuedUtc).TotalSeconds;
                    }
                }
                return(newToken);
            }
            catch (Newtonsoft.Json.JsonException ex)
            {
                logger.Error(ex, $"Exception was caught when deserializing {typeName}. Content is: {content}");
                throw new TokenResponseException(new TokenErrorResponse
                {
                    Error = "Server response does not contain a JSON object. Status code is: " + response.StatusCode
                }, response.StatusCode);
            }
        }
Example #15
0
		/// <summary>The default constructor for RevocationData.</summary>
		/// <remarks>The default constructor for RevocationData.</remarks>
		/// <param name="signedToken"></param>
		public RevocationData(SignedToken signedToken)
		{
			this.targetToken = signedToken;
		}
Example #16
0
 public void FromSignedToken_ThrowsIfIncorrectPartCount(string jwt)
 {
     Assert.Throws <InvalidJwtException>(
         () => SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(jwt));
 }
Example #17
0
 public void FromSignedToken_ThrowsIfNotValidJson()
 {
     Assert.Throws <JsonReaderException>(
         () => SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(
             "YmFzZV82NF9oZWFkZXJfbm9fanNvbg==.YmFzZV82NF9wYXlsb2FkX25vX2pzb24=.c2lnbmF0dXJl"));
 }
Example #18
0
        /// <param name="signedToken"></param>
        /// <param name="optionalSource"></param>
        /// <param name="validationDate"></param>
        /// <returns></returns>
        /// <exception cref="System.IO.IOException">An error occurs when accessing the CertificateSource
        ///     </exception>
        internal virtual CertificateAndContext GetIssuerCertificate(SignedToken signedToken
                                                                    , CertificateSource optionalSource, DateTime validationDate)
        {
            if (signedToken.GetSignerSubjectName() == null)
            {
                return(null);
            }
            IList <CertificateAndContext> list = new CompositeCertificateSource(trustedListCertificatesSource
                                                                                , optionalSource).GetCertificateBySubjectName(signedToken.GetSignerSubjectName()
                                                                                                                              );

            if (list != null)
            {
                foreach (CertificateAndContext cert in list)
                {
                    LOG.Info(cert.ToString());
                    if (validationDate != null)
                    {
                        try
                        {
                            cert.GetCertificate().CheckValidity(validationDate);
                        }
                        catch (CertificateExpiredException)
                        {
                            LOG.Info("Was expired");
                            continue;
                        }
                        catch (CertificateNotYetValidException)
                        {
                            LOG.Info("Was not yet valid");
                            continue;
                        }
                        if (cert.GetCertificateSource() == CertificateSourceType.TRUSTED_LIST && cert.GetContext
                                () != null)
                        {
                            ServiceInfo info = (ServiceInfo)cert.GetContext();
                            if (info.GetStatusStartingDateAtReferenceTime() != null && validationDate.CompareTo(                             //jbonilla Before
                                    info.GetStatusStartingDateAtReferenceTime()) < 0)
                            {
                                LOG.Info("Was not valid in the TSL");
                                continue;
                            }
                            else
                            {
                                if (info.GetStatusEndingDateAtReferenceTime() != null && validationDate.CompareTo(info                                 //jbonilla After
                                                                                                                  .GetStatusEndingDateAtReferenceTime()) > 0)
                                {
                                    LOG.Info("Was not valid in the TSL");
                                    continue;
                                }
                            }
                        }
                    }
                    if (signedToken.IsSignedBy(cert.GetCertificate()))
                    {
                        return(cert);
                    }
                }
            }
            return(null);
        }
Example #19
0
 public void FromSignedToken_ThrowsIfNotBase64()
 {
     Assert.Throws <FormatException>(
         () => SignedToken <JsonWebSignature.Header, JsonWebSignature.Payload> .FromSignedToken(
             "not_base64_header.not_base64_serialized_payload.signature"));
 }
Example #20
0
 /// <summary>The default constructor for RevocationData.</summary>
 /// <remarks>The default constructor for RevocationData.</remarks>
 /// <param name="signedToken"></param>
 public RevocationData(SignedToken signedToken)
 {
     this.targetToken = signedToken;
 }