Comment changer l'url de deploiement clickonce sans desinstallation / reinstallation

 

J'ai eu pour un cas de figure à regler pour un certain nombre de client , le serveur sur lequel etait deployé une application clickonce ne convenait plus et l'url indiquée etait une url locale du type http://monserveur/, il y avait une solution qui consistait à changer chaque fichiers "host" de chaque poste ou etait installé l'application et de faire pointer vers une nouvelle ip et sur le nouveau serveur ajouter le bon host header. Pas vraiment pratique, d'autant plus qu'il faut refaire cette manip pour les nouveaux clients.

Ensuite j'ai pensé à une desinstallation puis réinstallation sur chaque poste, les utilisateurs n'etant pas tous très "abiles" avec ces manipulations, il fallait que je me deplace sur chaque poste pour réaliser cette modification moi meme. Pas pratique non plus.

En regardant de plus près le manifest de deployement  , on peut voir dans la section <deployment><deploymentProvider> l'attribut codebase comme indiqué ici, celui-ci indique l'emplacement de deployement.

il suffit de modifier la valeur entrée par la nouvelle url de deployement, resigner le manifest avec le certificat, voici une petite methode pour le faire, le premier paramètre est l'emplacement du manifeste de deployement, le deuxieme est l'emplacement du certificat et le troisième est le mot de passe du certificat.

public static void SignFile(string manifestFileName, string certificatFileName, string password)
{
    Uri timestampUrl = null;
    X509Certificate2 cert = new X509Certificate2(certificatFileName, password);
    bool flag = false;
    X509Certificate2 storedCert = null;
    if (flag = ValidateCertificate(cert, certificatFileName))
    {
        storedCert = cert;
    }
    X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
    store.Open(OpenFlags.OpenExistingOnly);
    foreach (X509Certificate2 certificate2 in store.Certificates)
    {
        if ((certificate2.GetCertHashString().ToLower() == null) && (flag = ValidateCertificate(certificate2, null)))
        {
            storedCert = certificate2;
        }
    }
    SecurityUtilities.SignFile(storedCert, timestampUrl, manifestFileName);
}

Publier le nouveau manifest de deployement signé dans l'emplacement existant et surtout ne pas oublier de pusher les fichiers sur le nouvel emplacement.

2 commentaires:

Anonyme a dit…

Bonjour Marc, bien que l'article date de 2007, il me paraît correspondre exactement à ce que je cherche.

J'ai une partie du code que je n'arrive pas à utiliser : if (flag = ValidateCertificate(cert, certificatFileName)

ValidateCertificate correspond à une fonction que vous avez fait ou à une déclaration que je ne connais pas ?

Merci,
Pascal

Marc Chouteau a dit…

@Pascal,

Effectivement, au temps pour moi, il s'agit d'une fonction "custom" dont voici le code via reflector :

private static bool ValidateCertificate(X509Certificate2 cert, string hashOrPath)
{
bool flag = true;
if (!Certificate.CanSignWith(cert))
{
Console.WriteLine("InvalidCertUsage");
flag = false;
}
if (!Certificate.HasPrivateKey(cert))
{
Console.WriteLine("InvalidCertNoPrivateKey");
flag = false;
}
return flag;
}

internal class Certificate
{
// Fields
private static string szOID_CODE_SIGNING = "1.3.6.1.5.5.7.3.3";
private static string szOID_ENHANCED_KEY_USAGE = "2.5.29.37";
private static string szOID_KEY_USAGE = "2.5.29.15";

// Methods
public static bool CanSignWith(X509Certificate2 cert)
{
bool flag = true;
if (cert.Extensions.Count > 0)
{
foreach (X509Extension extension in cert.Extensions)
{
bool? nullable = null;
if (string.Compare(extension.Oid.Value, szOID_KEY_USAGE, true, CultureInfo.InvariantCulture) == 0)
{
X509KeyUsageExtension extension2 = new X509KeyUsageExtension();
extension2.CopyFrom(extension);
if ((extension2.KeyUsages & X509KeyUsageFlags.DigitalSignature) != X509KeyUsageFlags.None)
{
X509ExtensionEnumerator enumerator = cert.Extensions.GetEnumerator();
while (enumerator.MoveNext())
{
nullable = CodeSignEnhancedKeyPresent(enumerator.Current);
if (nullable.HasValue)
{
return nullable.Value;
}
}
return flag;
}
flag = false;
}
else
{
nullable = CodeSignEnhancedKeyPresent(extension);
if (nullable.HasValue && !nullable.Value)
{
flag = false;
}
}
}
}
return flag;
}

private static bool? CodeSignEnhancedKeyPresent(X509Extension extension)
{
bool? nullable = null;
if (string.Compare(extension.Oid.Value, szOID_ENHANCED_KEY_USAGE, true, CultureInfo.InvariantCulture) == 0)
{
X509EnhancedKeyUsageExtension extension2 = extension as X509EnhancedKeyUsageExtension;
if (extension2 != null)
{
OidEnumerator enumerator = extension2.EnhancedKeyUsages.GetEnumerator();
while (enumerator.MoveNext())
{
if (string.Compare(enumerator.Current.Value, szOID_CODE_SIGNING, true, CultureInfo.InvariantCulture) == 0)
{
nullable = true;
break;
}
}
}
if (!nullable.HasValue)
{
nullable = false;
}
}
return nullable;
}

public static bool HasPrivateKey(X509Certificate2 cert)
{
return (cert.PrivateKey != null);
}
}