4 votes

Comment obtenir une réponse SAML de la part d'OKTA pour les tests d'unité/d'intégration ?

Je travaille sur un projet où l'on s'authentifie via SAML à partir d'OKTA. J'ai réussi à faire fonctionner l'intégration où une réponse SAMLR est envoyée (via la méthode POST) au site web.

Dans la plus pure tradition TDD, j'ai commencé par écrire quelques tests unitaires. Mes tests unitaires prennent en compte une SAMLResponse (qui est encodée en Base64). Tous mes tests unitaires fonctionnent, cependant, parce qu'une SAMLResponse n'a qu'une durée de vie (expire) de quelques minutes, mes tests unitaires se cassent après quelques minutes.

Je dois donc me connecter périodiquement à OKTA, puis utiliser les outils de développement de Chrome pour capturer le trafic envoyé à mon site de développement. Je copie et colle ensuite la SAMLResponse dans mes tests unitaires et je recommence à passer les tests unitaires. Il est évident que cette situation n'est pas souhaitable.

Ma question est donc la suivante : comment puis-je me connecter à Okta de manière automatisée (de préférence en C#) pour obtenir une SAMLResponse ? Je suppose qu'il existe une URL à laquelle je peux envoyer un POST avec le nom d'utilisateur et le mot de passe et obtenir la SAMLReponse. Toutes mes tentatives de Fiddler pour essayer de comprendre la communication requise m'ont laissé frustré. Je suis à la recherche de tout conseil que vous pourriez avoir. Merci d'avance.

4voto

Ty Seddon Points 61

J'ai trouvé une solution qui fonctionne et je voulais la partager avec la communauté. Je ne suis pas sûr du protocole à suivre pour répondre à ma propre question en me basant sur les commentaires utiles d'autres auteurs (Joël Franusic). Si j'enfreins le protocole, veuillez me le faire savoir.

Merci à Joël Franusic pour les indications. J'ai implémenté sa solution 1.2 (User Agent avec le client Okta). Entre ses références et quelques autres éléments de documentation sur le site d'Okta, j'ai été capable d'assembler du code fonctionnel.

private static async Task<string> GetTestSamlResponse()
    {
        try
        {
            // settings specific to my Okta instance
            string username = "USERNAME GOES HERE";
            string password = "PASSWORD GOES HERE";
            var apiToken = "API TOKEN GOES HERE";

            // this is the unique domain issued to your account.  
            // If you setup a dev account you'll have a domain in the form https://dev-<AccountNumber>.oktapreview.com.
            // account number is a unique number issues by Okta when you sign up for the account
            var baseUrl = "YOUR BASE URL GOES HERE";

            // In Okta Admin UI, click "Applications" in main menu, choose your app, click "Sign On" tab.  Under Sign On Methods, then under SAML 2.0, click "View Setup Instructions"
            // Get the url called "Identity Provider Single Sign-On URL", paste it in th below line
            var ssoUrl = "YOUR SSO URL GOES HERE";

            // construct an Okta settings object
            var settings = new Okta.Core.OktaSettings
            {
                ApiToken = apiToken,
                BaseUri = new Uri(baseUrl)
            };

            // get session token from Okta
            var authClient = new Okta.Core.Clients.AuthClient(settings);
            var authResponse = authClient.Authenticate(username, password);
            var sessionToken = authResponse.SessionToken;

            // start session and get a cookie token
            var sessionsClient = new Okta.Core.Clients.SessionsClient(settings);
            var session = sessionsClient.CreateSession(sessionToken);
            var cookieToken = session.CookieToken;

            // using the cookie token, get the SAMLResponse from Okta via a HTTP GET.
            var httpClient = new System.Net.Http.HttpClient();

            // add User-Agent header, because apparently Okta is expecting this information.  
            // If you don't pass something, the Okta site will return a 500 - Internal Server error
            httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "UnitTest");

            // add the cookie token to the URL query string
            string url = string.Format("{0}?onetimetoken={1}", ssoUrl, cookieToken);

            // do the HTTP GET
            using (var response = await httpClient.GetAsync(url))
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    // read the HTML returned
                    string html = await response.Content.ReadAsStringAsync();

                    // parse the HTML to get the SAMLResponse (using HtmlAgilityPack from NuGet)
                    HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
                    htmlDoc.LoadHtml(html);
                    // from the input field called SAMLResponse, get the "value" attribute
                    string samlResponse = htmlDoc.DocumentNode.SelectSingleNode("//input[@name='SAMLResponse']").Attributes["value"].Value;
                    return samlResponse;
                }
                else
                    throw new Exception(string.Format("Error getting SAML Response {0}", response.StatusCode));
            }
        }
        catch (Exception ex)
        {
            throw;
        }
    }

2voto

Joël Franusic Points 970

Il existe plusieurs façons de réaliser le type de test que vous suggérez, voici celles qui me viennent immédiatement à l'esprit :

  1. Écrivez un simple "agent utilisateur" HTTP en C# en utilisant une bibliothèque telle que RestSharp ou similaire.
  2. Construisez un test d'intégration contre un IdP fictif externe.
  3. Modifiez le SAMLResponse et re-signez avec votre propre clé.

Je couvre chaque approche en détail ci-dessous.

Écriture d'un simple "agent utilisateur" HTTP

Je suggère cette méthode, je suggère d'adopter l'une des deux approches suivantes :

  1. Écrire un agent utilisateur générique qui détectera et remplira les champs de formulaire de nom d'utilisateur et de mot de passe. J'ai écrit un outil en Python appelé " saml-messenger "qui adopte cette approche, le code principal se trouve dans le fichier nommé messenger.py .
  2. Utilisez l'API d'Okta pour récupérer un jeton de session et l'utiliser pour obtenir un numéro d'identification de l'utilisateur. SAMLResponse . Le site okta-aws-cli-assume-role adopte cette approche. Le code pour Récupérer le jeton de session y échange de ce jeton de session contre une SAMLResponse se trouvent tous deux dans le src/main/java/com/okta/tools/awscli.java fichier.

La première approche est plus générique et devrait fonctionner avec n'importe quel IdP avec un champ de nom d'utilisateur et de mot de passe. La deuxième approche est probablement ce que vous recherchez, mais elle est spécifique à Okta.

Dans les deux cas, je vous suggère de créer un utilisateur spécial dans Okta qui sera verrouillé et utilisé uniquement pour les tests.

Construction d'un test d'intégration contre un IdP fictif

Cette approche consisterait à mettre en place un IdP fantaisie qui vous donnerait un SAMLResponse sans authentification, j'ai utilisé le saml-idp projet pour faire ça avant.

L'avantage de cette approche est qu'elle devrait nécessitent moins de C# à écrire, au prix de la prise en charge d'une autre dépendance.

Modification et re-signature d'un SAMLResponse

Je n'inclus cette option ici que par souci d'exhaustivité et pour vous mettre en garde contre cette approche. L'apprentissage de SAML vous mettra face à la folie et au regret. Je ne suggère pas cette approche.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X