/// <summary>
        /// GetBLOB method implmentation
        /// </summary>
        public override Task <MetadataBLOBPayload> GetBLOB()
        {
            bool needrawblob = false;
            MetadataBLOBPayload     result = null;
            BLOBPayloadInformations infos  = new BLOBPayloadInformations();

            if (HasBLOBPayloadCache())
            {
                infos = GetBLOBPayloadCache();
                if (string.IsNullOrEmpty(infos.BLOB))
                {
                    return(null);
                }
                int      oldnumber     = infos.Number;
                DateTime oldnextupdate = infos.NextUpdate;
                result = DeserializeAndValidateBlob(infos);
                if ((infos.Number > oldnumber) || (Convert.ToDateTime(infos.NextUpdate) > Convert.ToDateTime(oldnextupdate)))
                {
                    needrawblob = true;
                }
            }
            else
            {
                return(null);
            }
            if (needrawblob)
            {
                if (string.IsNullOrEmpty(infos.BLOB))
                {
                    return(null);
                }
                SetBLOBPayloadCache(infos);
            }
            return(Task.FromResult(result));
        }
Пример #2
0
        /// <summary>
        /// RetreiveBlobProperties method implementation
        /// </summary>
        protected virtual BLOBPayloadInformations RetreiveBlobProperties(BLOBPayloadInformations infos)
        {
            Dictionary <string, string> dic = DecodeNewPayload(infos.BLOB);
            var xnumber     = dic["Number"];
            var xnextupdate = dic["NextUpdate"];

            infos.Number     = Convert.ToInt32(xnumber);
            infos.NextUpdate = Convert.ToDateTime(xnextupdate);
            return(infos);
        }
Пример #3
0
 /// <summary>
 /// SetBLOBPayload method implmentation
 /// </summary>
 public void SetBLOBPayloadCache(BLOBPayloadInformations infos)
 {
     try
     {
         _manager.SetBLOBPayloadCache(infos);
     }
     catch (Exception e)
     {
         _log.WriteEntry(string.Format("Error on WebAdminService Service SetBLOBPayload method : {0}.", e.Message), EventLogEntryType.Error, 2010);
     }
 }
Пример #4
0
        /// <summary>
        /// SetBLOBPayloadCache method implmentation
        /// </summary>
        public void SetBLOBPayloadCache(BLOBPayloadInformations infos)
        {
            RegistryKey ek = Registry.LocalMachine.OpenSubKey("Software\\MFA", true);

            ek.SetValue("BlobNumber", Convert.ToString(infos.Number), RegistryValueKind.String);
            ek.SetValue("BlobNextUpdate", infos.NextUpdate.ToString("yyyy-MM-dd"), RegistryValueKind.String);
            ek.SetValue("BlobDownload", Convert.ToInt32(infos.CanDownload), RegistryValueKind.DWord);
            File.WriteAllText(SystemUtilities.PayloadCacheFile, infos.BLOB);
            using (MailSlotClient mailslot = new MailSlotClient("BDC"))
            {
                mailslot.Text = Environment.MachineName;
                mailslot.SendNotification(NotificationsKind.ConfigurationReload);
            }
        }
Пример #5
0
        /// <summary>
        /// Backgroud RefreshBLOBMethod  method
        /// </summary>
        private void RefreshBLOBMethod()
        {
            using (_blobcanceller.Token.Register(Thread.CurrentThread.Abort))
            {
                while (!_blobmustexit)
                {
                    try
                    {
                        lock (_bloblock)
                        {
                            BLOBPayloadInformations infos = GetBLOBPayloadCache();
                            if (infos.CanDownload && ((DateTime.Now > Convert.ToDateTime(infos.NextUpdate)) || (!File.Exists(SystemUtilities.PayloadCacheFile))))
                            {
                                try
                                {
                                    infos.BLOB = GetRawBlob().Result;
                                }
                                catch
                                {
                                    infos.BLOB = null;
                                }
                                if (!string.IsNullOrEmpty(infos.BLOB))
                                {
                                    int      oldnumber     = infos.Number;
                                    DateTime oldnextupdate = infos.NextUpdate;

                                    RetreiveBlobProperties(infos);
                                    if ((infos.Number > oldnumber) || (Convert.ToDateTime(infos.NextUpdate) > Convert.ToDateTime(oldnextupdate)) || (!File.Exists(SystemUtilities.PayloadCacheFile)))
                                    {
                                        SetBLOBPayloadCache(infos);
                                    }
                                }
                            }
                        }
                        Thread.Sleep(new TimeSpan(0, 12, 0, 0)); // every 12 hours
                    }
                    catch (ThreadAbortException ex)
                    {
                        _blobmustexit = true;
                        _log.WriteEntry(string.Format("error on refresh BLOB method : {0}.", ex.Message), EventLogEntryType.Error, 1014);
                    }
                    catch (Exception ex)
                    {
                        _log.WriteEntry(string.Format("error on refresh BLOB method : {0}.", ex.Message), EventLogEntryType.Error, 1014);
                        Thread.Sleep(new TimeSpan(0, 12, 0, 0)); // every 12 hours
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// GetBLOBPayloadCache method implementation
        /// </summary>
        protected virtual BLOBPayloadInformations GetBLOBPayloadCache()
        {
            BLOBPayloadInformations infos = new BLOBPayloadInformations();
            RegistryKey             ek    = Registry.LocalMachine.OpenSubKey("Software\\MFA", false);

            infos.Number      = Convert.ToInt32(ek.GetValue("BlobNumber", 0, RegistryValueOptions.None));
            infos.NextUpdate  = Convert.ToDateTime(ek.GetValue("BlobNextUpdate", "1970-01-01", RegistryValueOptions.None));
            infos.CanDownload = Convert.ToBoolean(ek.GetValue("BlobDownload", 1, RegistryValueOptions.None));
            if (File.Exists(SystemUtilities.PayloadCacheFile))
            {
                infos.BLOB = File.ReadAllText(SystemUtilities.PayloadCacheFile);
            }
            else
            {
                infos.BLOB = null;
            }
            return(infos);
        }
        /// <summary>
        /// SetBLOBPayloadCache method implmentation
        /// </summary>
        public static void SetBLOBPayloadCache(BLOBPayloadInformations infos)
        {
            WebAdminClient manager = new WebAdminClient();

            manager.Initialize();
            try
            {
                IWebAdminServices client = manager.Open();
                try
                {
                    client.SetBLOBPayloadCache(infos);
                }
                finally
                {
                    manager.Close(client);
                }
            }
            finally
            {
                manager.UnInitialize();
            }
        }
 protected abstract MetadataBLOBPayload DeserializeAndValidateBlob(BLOBPayloadInformations infos);
 /// <summary>
 /// SetBLOBPayloadCache method implementation
 /// </summary>
 protected virtual void SetBLOBPayloadCache(BLOBPayloadInformations infos)
 {
     WebAdminManagerClient.SetBLOBPayloadCache(infos);
 }
        /// <summary>
        /// DeserializeAndValidateBlob method implementation
        /// </summary>
        protected override MetadataBLOBPayload DeserializeAndValidateBlob(BLOBPayloadInformations infos)
        {
            if (string.IsNullOrWhiteSpace(infos.BLOB))
            {
                throw new ArgumentNullException(nameof(infos.BLOB));
            }

            var jwtParts = infos.BLOB.Split('.');

            if (jwtParts.Length != 3)
            {
                throw new ArgumentException("The JWT does not have the 3 expected components");
            }

            var blobHeaderString = jwtParts.First();
            var blobHeader       = JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(blobHeaderString)));

            var blobAlg = blobHeader["alg"]?.Value <string>();

            if (blobAlg == null)
            {
                throw new ArgumentNullException("No alg value was present in the BLOB header.");
            }

            JArray x5cArray = blobHeader["x5c"] as JArray;

            if (x5cArray == null)
            {
                throw new Exception("No x5c array was present in the BLOB header.");
            }

            var keyStrings = x5cArray.Values <string>().ToList();

            if (keyStrings.Count == 0)
            {
                throw new ArgumentException("No keys were present in the BLOB header.");
            }

            var rootCert  = GetX509Certificate(ROOT_CERT);
            var blobCerts = keyStrings.Select(o => GetX509Certificate(o)).ToArray();

            var keys = new List <SecurityKey>();

            foreach (var certString in keyStrings)
            {
                var cert = GetX509Certificate(certString);

                var ecdsaPublicKey = cert.GetECDsaPublicKey();
                if (ecdsaPublicKey != null)
                {
                    keys.Add(new ECDsaSecurityKey(ecdsaPublicKey));
                    continue;
                }

                var rsaPublicKey = cert.GetRSAPublicKey();
                if (rsaPublicKey != null)
                {
                    keys.Add(new RsaSecurityKey(rsaPublicKey));
                    continue;
                }
                throw new MetadataException("Unknown certificate algorithm");
            }
            var blobPublicKeys = keys.ToArray();

            var certChain = new X509Chain();

            certChain.ChainPolicy.ExtraStore.Add(rootCert);
            certChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

            var validationParameters = new TokenValidationParameters
            {
                ValidateIssuer           = false,
                ValidateAudience         = false,
                ValidateLifetime         = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKeys        = blobPublicKeys,
            };

            var tokenHandler = new JwtSecurityTokenHandler()
            {
                // 250k isn't enough bytes for conformance test tool
                // https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1097
                MaximumTokenSizeInBytes = infos.BLOB.Length
            };

            tokenHandler.ValidateToken(
                infos.BLOB,
                validationParameters,
                out var validatedToken);

            if (blobCerts.Length > 1)
            {
                certChain.ChainPolicy.ExtraStore.AddRange(blobCerts.Skip(1).ToArray());
            }

            var certChainIsValid = certChain.Build(blobCerts.First());

            // if the root is trusted in the context we are running in, valid should be true here
            if (!certChainIsValid)
            {
                // otherwise we have to manually validate that the root in the chain we are testing is the root we downloaded
                if (rootCert.Thumbprint == certChain.ChainElements[certChain.ChainElements.Count - 1].Certificate.Thumbprint &&
                    // and that the number of elements in the chain accounts for what was in x5c plus the root we added
                    certChain.ChainElements.Count == (keyStrings.Count + 1) &&
                    // and that the root cert has exactly one status listed against it
                    certChain.ChainElements[certChain.ChainElements.Count - 1].ChainElementStatus.Length == 1 &&
                    // and that that status is a status of exactly UntrustedRoot
                    certChain.ChainElements[certChain.ChainElements.Count - 1].ChainElementStatus[0].Status == X509ChainStatusFlags.UntrustedRoot)
                {
                    // if we are good so far, that is a good sign
                    certChainIsValid = true;
                    for (var i = 0; i < certChain.ChainElements.Count - 1; i++)
                    {
                        // check each non-root cert to verify zero status listed against it, otherwise, invalidate chain
                        if (0 != certChain.ChainElements[i].ChainElementStatus.Length)
                        {
                            certChainIsValid = false;
                        }
                    }
                }
            }

            if (!certChainIsValid)
            {
                throw new VerificationException("Failed to validate cert chain while parsing BLOB");
            }

            var blobPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson();

            var blob = JsonConvert.DeserializeObject <MetadataBLOBPayload>(blobPayload);

            infos.Number      = blob.Number;
            infos.NextUpdate  = Convert.ToDateTime(blob.NextUpdate);
            infos.CanDownload = false; // Constrained Repository
            blob.JwtAlg       = blobAlg;
            return(blob);
        }