From 2ecaeec8a72f9e125b1e2d57dab7bc1763e0b5a3 Mon Sep 17 00:00:00 2001 From: cailbourdin Date: Tue, 9 Jul 2024 11:05:43 +0200 Subject: [PATCH] test: ajout d'un test de validation du ST dans le CI --- README.md | 2 +- ci/python/fake_service.py | 53 ++++++++++++++++++++++++++++++++++++ puppeteer/run.sh | 9 ++++-- puppeteer/scenarios/basic.js | 31 +++++++++++++++------ 4 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 ci/python/fake_service.py diff --git a/README.md b/README.md index ff0a89c..eea9910 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ There is also a number of custom properties that are defined for some custom enh | cas.custom.properties.interrupt.structs-refresh-cache-interval | Description | PT6H | -# CI pipeline with puppeteer and github actions +# CI Pipeline ## Puppeteer diff --git a/ci/python/fake_service.py b/ci/python/fake_service.py new file mode 100644 index 0000000..cdeb7c2 --- /dev/null +++ b/ci/python/fake_service.py @@ -0,0 +1,53 @@ +""" +Serveur python simulant un service web. +Il n'est pas là pour faire les requêtes (ce sont les scripts de test qui les font) mais il est là +pour avoir une réponse aux redirections et pour faire valider des ST. +""" + +import urllib3 +import requests +from http.server import BaseHTTPRequestHandler, HTTPServer + +urllib3.disable_warnings() + +CAS_BASE_URL = "https://localhost:8443/cas" +SERVICE_URL = "http://localhost:8002/test" + +class RequestHandler(BaseHTTPRequestHandler): + """ + Classe RequestHandler pour répondre aux différentes requêtes + """ + def do_GET(self): + """ + Réponse aux requêtes GET. + """ + if 'ticket' in self.path: + # On fait valider le ST au serveur CAS : si le serveur CAS répond OK alors on répondra OK aussi + ST = self.path.split('ticket')[1] + ST = ST[1:len(ST)] + request_url = CAS_BASE_URL+"/serviceValidate?service="+SERVICE_URL+"&ticket="+ST + response = requests.get(request_url, verify=False) + # Si on a cas:authenticationSuccess alors c'est OK + if ('cas:authenticationSuccess' in response.text) and (response.status_code==200): + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.end_headers() + self.wfile.write("SUCCESS".encode('utf-8')) + # Sinon on a eu un problème donc on retourne un 404 + else: + self.send_response(404) + self.end_headers() + self.wfile.write(b'404 Not Found') + else: + self.send_response(404) + self.end_headers() + self.wfile.write(b'404 Not Found') + +def run(server_class=HTTPServer, handler_class=RequestHandler, port=8002): + server_address = ('', port) + httpd = server_class(server_address, handler_class) + print(f'Starting server on port {port}...') + httpd.serve_forever() + +if __name__ == '__main__': + run() diff --git a/puppeteer/run.sh b/puppeteer/run.sh index c23c14a..21acbf6 100755 --- a/puppeteer/run.sh +++ b/puppeteer/run.sh @@ -66,12 +66,16 @@ cd "${ROOT_DIRECTORY}/ci/ldap" ./run-ldap.sh cd "${ROOT_DIRECTORY}/ci/redis" ./start-all.sh +# Démarrage du serveur python +cd "${ROOT_DIRECTORY}/ci/python" +python3 fake_service.py & +pid_python=$! cd "${ROOT_DIRECTORY}" # Lancement du serveur CAS grâce au war qu'on a construit plus haut echo "Launching CAS at $casWebApplicationFile with options $CAS_ARGS" java -jar "$casWebApplicationFile" $CAS_ARGS & -pid=$! +pid_cas=$! echo "Waiting for CAS under process id ${pid}" sleep 45 casLogin="${PUPPETEER_CAS_HOST:-https://localhost:8443}/cas/login" @@ -105,7 +109,8 @@ for scenario in "${PWD}"/puppeteer/scenarios/*; do done; # On kill le serveur CAS et les docker avant de terminer le script -kill -9 "$pid" +kill -9 "$pid_cas" +kill -9 "$pid_python" cd "${ROOT_DIRECTORY}/ci/ldap" ./stop-ldap.sh cd "${ROOT_DIRECTORY}/ci/redis" diff --git a/puppeteer/scenarios/basic.js b/puppeteer/scenarios/basic.js index eeaae45..18600fe 100644 --- a/puppeteer/scenarios/basic.js +++ b/puppeteer/scenarios/basic.js @@ -10,38 +10,51 @@ const logger = pino({ (async () => { const browser = await puppeteer.launch({ - headless: (process.env.CI === "true" || process.env.HEADLESS === "true") ? "new" : false, + headless: true, ignoreHTTPSErrors: true, devtools: false, defaultViewport: null, - slowMo: 5, - args: ['--start-maximized', "--window-size=1920,1080"] + slowMo: 5 }); try { const page = await browser.newPage(); + const client = await page.createCDPSession(); + const casHost = "https://localhost:8443"; + const service = "http://localhost:8002/test" - const casHost = process.env.PUPPETEER_CAS_HOST || "https://localhost:8443"; - await page.goto(`${casHost}/cas/login`); + // Go to login page + await page.goto(`${casHost}/cas/login?service=${service}`); + // Type credentials await page.waitForSelector("#username", {visible: true}); await page.$eval("#username", el => el.value = ''); await page.type("#username", "test1"); - await page.waitForSelector("#password", {visible: true}); await page.$eval("#password", el => el.value = ''); await page.type("#password", "test"); + // Validate credentials and send request to CAs await page.keyboard.press('Enter'); await page.waitForNavigation(); - const cookies = (await page.cookies()).filter(c => { + // Storage.getCookies can get all cookies from browser (page cookies are not enough) + const cookies = (await client.send('Storage.getCookies')).cookies; + logger.info(`Cookie:\n${JSON.stringify(cookies, undefined, 2)}`); + + // Verify that we have the TGC + const tgc = cookies.filter(c => { logger.debug(`Checking cookie ${c.name}:${c.value}`); return c.name === "TGC"; }); - assert(cookies.length !== 0); - logger.info(`Cookie:\n${JSON.stringify(cookies, undefined, 2)}`); + assert(tgc.length !== 0); + + // Also verify that the ST was successfully validated (if it is the case then the service should reponse with a 200) + const pageContent = await page.content(); + assert(pageContent.includes("SUCCESS")) + await process.exit(0) + } catch (e) { logger.error(e); await process.exit(1)