Articles / Nouvelle technologies


Heureusement que Fred Cavazza en parle, car l'actualité ne fait pas beaucoup de bruit! Microsoft, Google, IBM, VerySign, rejoigne Yahoo en tant que fournisseur d'identité (OpenID Provider). Du coup c'est des millions de personnes qui vont posséder une identité OpenID! Le but étant, pour l'utilisateur, d'avoir une seul identité peu importe le service (site) qu'il veut rejoindre. Pourquoi je vous en parle? Car vous êtes peut-être résponsable de la création d'un site internet. Imaginez que l'utilisateur n'ai pas besoin de s'inscrire pour utiliser votre service. Il pourrait directement se connecter avec ses identifiants OpenID.

Remarquez tout de même que OpenID ne gère que l'authentification et pas le profil -> ça impose toujours de devoir stocker le profil de l'utilisateur.

Alors, comment l'implémenter en ASP.NET?

D'abord, vous avez besoin d'avoir un compte OpenID pour pouvoir tester! Personnellement, j'en ai un sur myOpenID.

Lorsque vous êtes inscrit, vous obtenez une URI : c'est votre identifiant OpenID. Par exemple, le mien c'est : http://loicbar.myopenid.com/

On peut maintenant commencer, le but du jeu c'est de partir de rien, il n'y a aucune DLL derrière, on va juste tenter de se connecter et de récupérer certaines informations de notre compte OpenID :

    * Nom
    * Email
    * Pays
    * Langue

Notre page ASPx est très simple :

[code:xml]<asp:TextBox runat="server" ID="txtOpenId" Width="200" /><asp:Button runat="server" ID="btnLogon" Text="Login" OnClick="btnLogon_Click" />[/code]

Nous avons une textbox et un bouton qui vont nous permettre de nous connecter. Sur l'événement "click" nous allons demander une connexion au niveau du provider (myopenid dans mon cas).

La première chose à faire, c'est de savoir qui est notre provider. Rien de plus simple.

Votre identifiant est une URI qui correspond a une page HTML. Dans cette page HTML, on peut facilement retrouver les différentes informations (adresse du provider etc) à l'aide de tag définis sur la page :

[code:xml]<link rel="openid.server" href="http://www.myopenid.com/server" /><link rel="openid2.provider" href="http://www.myopenid.com/server" />[/code]

Nous pouvons donc créer un WebClient, télécharger le HTML et aller rechercher les différentes informations :

[code:c#]
public static StringDictionary GetIdentityServer(string identity)
{
    using (WebClient client = new WebClient())
    {
        string html = client.DownloadString(identity);
        StringDictionary col = new StringDictionary();

        foreach (Match match in REGEX_LINK.Matches(html))
        {
            AssignValue(match, col, "openid.server");
            AssignValue(match, col, "openid.delegate");
        }

        return col;
    }
}
[/code]

Au niveau de la regex nous aurons :

[code:c#]
private static readonly Regex REGEX_LINK = new Regex(@"<link[^>]*/?>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
[/code]

AsignValue permet seulement de prendre les différentes valeurs qui nous intéresse afin de les mettre dans une collection de string :

[code:c#]
private static void AssignValue(Match linkMatch, StringDictionary col, string name)
    {
        if (linkMatch.Value.IndexOf(name) > 0)
        {
            Match hrefMatch = REGEX_HREF.Match(linkMatch.Value);
            if (hrefMatch.Success)
            {
                if (!col.ContainsKey(name))
                    col.Add(name, hrefMatch.Groups[1].Value);
            }
        }
    }
[/code]

Même chose, ici on récupére l'URL à l'aide de la regex suivante :

[code:c#]
private static readonly Regex REGEX_HREF = new Regex("href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|(?<1>\\S+))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
[/code]

Au niveau de notre code de login, on aurait donc :

[code:c#]
public static bool Login(string identity, string requiredParameters, string optionalParameters)
{
    try
    {
        StringDictionary dic = GetIdentityServer(identity);
        string server = dic["openid.server"];
        string delgate = dic["openid.delegate"] ?? identity;

        if (!string.IsNullOrEmpty(server))
        {
            string redirectUrl = CreateRedirectUrl(requiredParameters, optionalParameters, delgate, identity);
            OpenIdData data = new OpenIdData(identity);
            HttpContext.Current.Session["openid"] = data;

            HttpContext.Current.Response.Redirect(server + redirectUrl, true);
        }
    }
    catch (Exception)
    { }

    return false;
}
[/code]

On a ici deux trois paramètre :

    * identity : c'est notre login OpenID
    * requiredParameters : La liste des paramètres requis
    * optionalParameters : La liste des paramètres optionnels

Les deux derniers paramètres ont la forme suivante :

"email,fullname,..."

Bien remarquer aussi que l'on met nos data dans une session, ce qui va nous permettre de plus tard, vérifié que la personne qui s'ai loguée est bien celle qui a demandé l'authentification.

Ensuite, il suffit de créer la redirection (on crée une URL en fonction des informations) :

[code:c#]
private static string CreateRedirectUrl(string requiredParameters, string optionalParameters, string delgate, string identity)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("?openid.ns=" + HttpUtility.UrlEncode("">http://specs.openid.net/auth/2.0"));
        sb.Append("&openid.mode=checkid_setup");
        sb.Append("&openid.identity=" + HttpUtility.UrlEncode(delgate));
        sb.Append("&openid.claimed_id=" + HttpUtility.UrlEncode(identity));
        sb.Append("&openid.return_to=" + HttpUtility.UrlEncode(HttpContext.Current.Request.Url.ToString()));

        if (!string.IsNullOrEmpty(requiredParameters) || !string.IsNullOrEmpty(optionalParameters))
        {
            sb.Append("&openid.ns.sreg=" + HttpUtility.UrlEncode("">http://openid.net/extensions/sreg/1.1"));

            if (!string.IsNullOrEmpty(requiredParameters))
                sb.Append("&openid.sreg.required=" + HttpUtility.UrlEncode(requiredParameters));

            if (!string.IsNullOrEmpty(optionalParameters))
                sb.Append("&openid.sreg.optional=" + HttpUtility.UrlEncode(optionalParameters));
        }

        return sb.ToString();
    }
[/code]

Par exemple, sur le click du bouton, nous aurons :

[code:c#]
public void btnLogon_Click(object sender, EventArgs e)
{
    bool success = OpenID.Login(txtOpenId.Text, "email,fullname", "country,language");

    if (!success)
    {
        Response.Write("The OpenID is not valid");
    }
}
[/code]

Ce click va causé un postback et lors de celui-ci, on va rechercher les différentes informations envoyée par le provider :

[code:c#]
protected void Page_Load(object sender, EventArgs e)
{
    if (OpenID.IsOpenIdRequest)
    {
        OpenIdData data = OpenID.Authenticate();
        if (data.IsSuccess)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<b>OpenID: {0}</b><br />", data.Identity);
            sb.AppendFormat("email: {0}<br />", data.Parameters["email"]);
            sb.AppendFormat("fullname: {0}<br />", data.Parameters["fullname"]);
            sb.AppendFormat("country: {0}<br />", data.Parameters["country"]);
            sb.AppendFormat("language: {0}<br />", data.Parameters["language"]);

            Response.Write(sb.ToString());
        }
    }
}
[/code]

Première vérification : est-ce qu'on a bien reçu une authentification :

[code:c#]
public static bool IsOpenIdRequest
    {
        get
        {
            if (!HttpContext.Current.Request.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))
                return false;

            return HttpContext.Current.Request.QueryString["openid.mode"] != null;
        }
    }
[/code]

Ce qui revient a dire, est-ce que nous avez reçu un get et dans ce get avons-nous une valeur pour openid.mode? Si oui, on s'authentifie :

[code:c#]
public static OpenIdData Authenticate()
{
    OpenIdData data = (OpenIdData)HttpContext.Current.Session["openid"];
    if (data == null)
        return new OpenIdData(string.Empty);

    NameValueCollection query = HttpContext.Current.Request.QueryString;

    if (query["openid.claimed_id"] != data.Identity)
        return data;

    data.IsSuccess = query["openid.mode"] == "id_res";

    foreach (string name in query.Keys)
    {
        if (name.StartsWith("openid.sreg."))
            data.Parameters.Add(name.Replace("openid.sreg.", string.Empty), query[name]);
    }

    HttpContext.Current.Session.Remove("openid");
    return data;
}
[/code]

On récupère nos data, on vérifie que celui qui s'authentifie est bien celui qui a voulu s'authentifier. Ensuite on regarde si l'authentification a réussi et pour finir on va rechercher les différents éléments qu'on met dans nos datas. Les informations que nous intéresse sont dans le GET et commence par "openid.sreg". Data c'est quoi? c'est :

[code:c#]
public class OpenIdData
{

    public OpenIdData(string identity)
    {
        Identity = identity;
    }

    public bool IsSuccess;
    public string Identity;
    public NameValueCollection Parameters = new NameValueCollection();
}
[/code]

Ensuite, il ne reste plus qu'a afficher les données (voir le Page_Load).

C'est du gâteau!

PS : Merci à Benoît Dion qui nous a retrouvé l'auteur du code : Mads Kristensen. (Moi même l'ayant trouvé un site de code OpenSource)



Lire la suite...
Tags:
Catégorie : ASP.NET

Une question sur cet article? n'hésitez pas a me contacter par Live Messegner. Suis-je connecté?

Soyez le premier à noter ce billet

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Par Loïc Bar le 14/02/2008 16:01:55

Permalink | Commentaires (1) | Post RSS |


Commentaires

27/02/2008 13:34:54

Loic Bar

Désolé de supprimer les commentaires mais faut pas dire de bétise Smile :
Citation : "PS : Merci à Benoît Dion qui nous a retrouvé l'auteur du code : Mads Kristensen. (Moi même l'ayant trouvé un site de code OpenSource)"

Loic Bar be

Ajouter un commentaire



(Affichera votre icône Gravatar)  

  Country flag










Propulsé par BlogEngine.NET, modifé par Loïc Bar.