En septembre 2025, lâun de nos clients nous a demandĂ© de nous concentrer sur un produit spĂ©cifique : lâActivID Appliance par HID. Selon le fournisseur, ce produit est utilisĂ© dans le monde entier pour sĂ©curiser lâaccĂšs aux infrastructures et aux donnĂ©es critiques. Il prend en charge une large gamme de mĂ©thodes dâauthentification, notamment lâauthentification push, le code Ă usage unique (OTP), les informations dâidentification PKI et les informations dâidentification statiques. Dans cet article, nous vous prĂ©senterons la mĂ©thodologie que nous avons utilisĂ©e pour dĂ©couvrir HID-PSA-2025-002, un contournement dâauthentification dans lâAPI SOAP pouvant mener Ă un accĂšs administratif sur lâapplication.
Vous souhaitez amĂ©liorer vos compĂ©tences ? DĂ©couvrez nos sessions de formation ! âŠ
En septembre 2025, lâun de nos clients nous a demandĂ© de nous concentrer sur un produit spĂ©cifique : lâActivID Appliance par HID. Selon le fournisseur, ce produit est utilisĂ© dans le monde entier pour sĂ©curiser lâaccĂšs aux infrastructures et aux donnĂ©es critiques. Il prend en charge une large gamme de mĂ©thodes dâauthentification, notamment lâauthentification push, le code Ă usage unique (OTP), les informations dâidentification PKI et les informations dâidentification statiques. Dans cet article, nous vous prĂ©senterons la mĂ©thodologie que nous avons utilisĂ©e pour dĂ©couvrir HID-PSA-2025-002, un contournement dâauthentification dans lâAPI SOAP pouvant mener Ă un accĂšs administratif sur lâapplication.
Vous souhaitez améliorer vos compétences ? Découvrez nos sessions de formation ! En savoir plus
Avant-propos
Cet article est volontairement dĂ©taillĂ© pour prĂ©senter autant dâaspects mĂ©thodologiques que possible concernant lâanalyse de code en boĂźte blanche. Si seule la partie expliquant la vulnĂ©rabilitĂ© vous intĂ©resse, veuillez vous rĂ©fĂ©rer Ă lâavis de sĂ©curitĂ© HID-PSA-2025-002 ou sauter directement Ă la section dâinvestigation.
Identification du produit
Notre premier objectif Ă©tait dâidentifier la version exacte du produit, car plusieurs versions Ă©taient disponibles sur la page de tĂ©lĂ©chargement de HID. La seule information que notre client nous avait fournie Ă©tait lâURL de lâapplication. Ă partir de lĂ , le seul artefact de version que nous avons remarquĂ© Ă©tait lâidentifiant suivant, trouvĂ© dans le footer HTML de lâinstance de notre client :

Cet identifiant, v080620, **nâa pu ĂȘtre trouvĂ© que dans la version 8.5 **de leur EULA (Contrat de Licence Utilisateur Final) au format PDF, disponible au tĂ©lĂ©chargement sur leur site web :

En suivant le guide dâinstallation, nous avons obtenu une instance virtualisĂ©e VMware de la solution dans sa version 8.5, nous donnant un accĂšs root complet sur la machine.
DĂ©couverte de la surface dâattaque
Cette partie peut sembler assez ennuyeuse au premier abord, mais obtenir une bonne comprĂ©hension des routes et services exposĂ©s est une Ă©tape clĂ© pour une analyse en boĂźte blanche. Dans le cas de cette recherche, nous pensons que lâanalyse mĂ©ticuleuse de chaque service a grandement contribuĂ© Ă la dĂ©couverte de la vulnĂ©rabilitĂ©.
Ătant donnĂ© que notre recherche se base sur la surface non authentifiĂ©e, Ă distance, un premier scan nmap est effectuĂ© :
$ nmap -p- -sV hid --open
PORT STATE SERVICE VERSION
40/tcp open ssh OpenSSH 7.4 (protocol 2.0)
443/tcp open ssl/http nginx
1005/tcp open ssl/http nginx
8443/tcp open ssl/http nginx
Une fois authentifié sur la VM (Machine Virtuelle), nous avons commencé à énumérer les services en écoute :
$ ss -ntalp
State Local Address:Port Process
LISTEN 0.0.0.0:3000 users:(("java",pid=3038,fd=58))
LISTEN 127.0.0.1:7800 users:(("java",pid=3038,fd=55))
LISTEN 127.0.0.1:25 users:(("master",pid=1821,fd=13))
LISTEN 0.0.0.0:61626 users:(("java",pid=3446,fd=990))
LISTEN 127.0.0.1:8443 users:(("java",pid=3446,fd=1009))
LISTEN 192.168.116.128:8443 users:(("java",pid=3446,fd=1008))
LISTEN 0.0.0.0:443 users:(("nginx",pid=1435,fd=6))
LISTEN 127.0.0.1:8445 users:(("java",pid=3446,fd=1010))
LISTEN 192.168.116.128:8445 users:(("java",pid=3446,fd=1007))
LISTEN 127.0.0.1:2016 users:(("oraagent.bin",pid=2049,fd=126))
LISTEN 127.0.0.1:50403 users:(("java",pid=3038,fd=57))
LISTEN 0.0.0.0:5093 users:(("lserv",pid=1357,fd=4))
LISTEN 0.0.0.0:40 users:(("sshd",pid=1360,fd=3))
LISTEN 127.0.0.1:9002 users:(("java",pid=3446,fd=694))
LISTEN 192.168.116.128:9002 users:(("java",pid=3446,fd=693))
LISTEN 0.0.0.0:1005 users:(("nginx",pid=1435,fd=8))
LISTEN 0.0.0.0:1006 users:(("nginx",pid=1435,fd=12))
LISTEN 127.0.0.1:56367 users:(("ocssd.bin",pid=2179,fd=137))
LISTEN 127.0.0.1:1007 users:(("miniserv.pl",pid=1858,fd=4))
LISTEN 0.0.0.0:61616 users:(("java",pid=3446,fd=989))
LISTEN 0.0.0.0:1008 users:(("nginx",pid=1435,fd=10))
LISTEN 192.168.116.128:1521 users:(("tnslsnr",pid=2080,fd=16))
LISTEN 127.0.0.1:1521 users:(("tnslsnr",pid=2080,fd=7))
LISTEN 0.0.0.0:1009 users:(("nginx",pid=1435,fd=14))
LISTEN *:50061 users:(("ora_d000_ftress",pid=2513,fd=44))
Pour faire court, les points suivants prĂ©sentent un intĂ©rĂȘt :
Les processus Java qui sont en écoute sur les ports 8443, 8445, 1005 et 1006.
Le proxy inverse Nginx qui a pu ĂȘtre vu sur le port 443 lors du scan nmap.
On peut remarquer que ces processus Java nâĂ©taient pas dĂ©tectĂ©s lors de lâutilisation de nmap, cela peut sâexpliquer en listant les rĂšgles de pare-feu :
$ iptables -nvL
[...]
Chain IN_public_allow (1 references)
pkts bytes target prot opt in out source destination
15719 943K ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 ctstate NEW,UNTRACKED
17 1020 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:1005 ctstate NEW,UNTRACKED
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:1006 ctstate NEW,UNTRACKED
0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:1812 ctstate NEW,UNTRACKED
10 536 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:40 ctstate NEW,UNTRACKED
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate NEW,UNTRACKED mark match 0x64
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate NEW,UNTRACKED mark match 0x65
Pour le protocole TCP, seuls les ports 40, 443 (HTTPS), 1005 et 1006 sont autorisĂ©s Ă ĂȘtre atteints.
Ătant donnĂ© que le port 443 est ouvert sur internet, commençons par comprendre comment le proxy Nginx est configurĂ©.
Investigation du service Nginx
Lâanalyse de la configuration Nginx commence par la lecture du fichier /etc/nginx :
user nginx;
worker_processes 2;
http {
include /etc/nginx/conf.d/*.conf;
}
Dans notre cas, ce fichier de configuration principal inclut uniquement tout autre fichier de configuration présent dans le dossier /etc/nginx/conf.d/ :
$ ls -l /etc/nginx/conf.d/*.conf
-rwx------ 1 root root 2005 Jun 20 2017 /etc/nginx/conf.d/default.conf
-rw-r--r-- 1 root root 652 Dec 18 2020 /etc/nginx/conf.d/web_activid.conf
Le fichier dâintĂ©rĂȘt est web_activid.conf⣠:
upstream weblogic8445 {
keepalive 30;
server 127.0.0.1:8445;
}
upstream weblogic8443 {
keepalive 30;
server 127.0.0.1:8443;
}
upstream webmin {
server 127.0.0.1:1007;
}
include /etc/nginx/include/TLS1.conf;
include /etc/nginx/include/TLS2.conf;
include /etc/nginx/include/TLS3.conf;
include /etc/nginx/include/MTLS1.conf;
include /etc/nginx/include/MTLS2.conf;
Deux dĂ©clarations dâupstream sont faites : weblogic8443 et weblogic8445, pointant respectivement vers des services HTTP sur les ports 8445 et 8443 de localhost. Les upstreams sont utilisĂ©s pour dĂ©finir des serveurs qui peuvent ensuite ĂȘtre rĂ©fĂ©rencĂ©s dans lâensemble de la configuration du serveur Nginx. AprĂšs cela, dâautres fichiers de configuration sont inclus, qui pourraient dĂ©finir des services TLS et des services TLS avec authentification mutuelle, selon leur nommage.
Le fichier /etc/nginx/include/TLS1.conf est le suivant :
server {
listen 443 ssl ;
listen [::]:443 ssl ;
ssl_verify_client off;
# ...
set $upstream weblogic8445;
# ...
include /etc/nginx/include/app/TLS1/*.conf;
}
En ce qui concerne les autres fichiers de configuration TLS2.conf, TLS3.conf, MTL3.conf et MTLS2.conf, ceux-ci ne seront pas explorĂ©s, car ils font rĂ©fĂ©rence Ă des services qui ne sont pas accessibles depuis internet, ou qui nĂ©cessitent une authentification mutuelle Ă lâaide dâun certificat client.
Pour revenir à la configuration TLS1, ici, un serveur écoutant sur le port 443 est déclaré, il définit une variable $upsteam à weblogic8445, et certaines configurations de serveur situées dans /etc/nginx/include/app/TLS1 sont incluses :
$ ls -l /etc/nginx/include/app/TLS1
total 0
lrwxrwxrwx 1 root root 48 Sep 2 17:11 AuthenticationPortal.conf -> /etc/nginx/include/app/AuthenticationPortal.conf
lrwxrwxrwx 1 root root 39 Sep 2 17:11 HealthCheck.conf -> /etc/nginx/include/app/HealthCheck.conf
lrwxrwxrwx 1 root root 45 Sep 2 17:11 ManagementConsole.conf -> /etc/nginx/include/app/ManagementConsole.conf
lrwxrwxrwx 1 root root 32 Sep 2 17:11 Root.conf -> /etc/nginx/include/app/Root.conf
lrwxrwxrwx 1 root root 35 Sep 2 17:11 SCIMAPI.conf -> /etc/nginx/include/app/SCIMAPI.conf
lrwxrwxrwx 1 root root 45 Sep 2 17:11 SelfServicePortal.conf -> /etc/nginx/include/app/SelfServicePortal.conf
lrwxrwxrwx 1 root root 35 Sep 2 17:11 SoapAPI.conf -> /etc/nginx/include/app/SoapAPI.conf
Ces fichiers sont tous des liens symboliques vers leur fichiers équivalents dans /etc/nginx/include/app/. Par exemple, le fichier AuthenticationPortal.conf :
location /idp/ {
proxy_pass https://$upstream;
}
# OpenID
location ~ /idp/[^/]+/authn/ {
proxy_pass https://$upstream;
include /etc/nginx/include/openiderrorhandling.conf;
}
De maniĂšre similaire, le fichier SoapAPI.conf :
location ^~ /4TRESS/ {
proxy_pass https://$upstream;
limit_except POST {
deny all;
}
if ($request_uri ~* "(?:wsdl|xsd)$") {
return 404;
}
include /etc/nginx/include/soaperrorhandling.conf;
}
location ^~ /ac-iasp-backend-jaxws/ {
proxy_pass https://$upstream;
limit_except POST {
deny all;
}
if ($request_uri ~* "(?:wsdl|xsd)$") {
return 404;
}
include /etc/nginx/include/soaperrorhandling.conf;
}
Nous pouvons observer que ces fichiers de configuration suivent la mĂȘme logique basĂ©e sur une directive location. Par exemple pour /idp/, ils re-routent la requĂȘte HTTP vers un serveur dĂ©fini par une variable $upstream. Cette variable a Ă©tĂ© dĂ©finie prĂ©cĂ©demment, en lâoccurrence comme weblogic8445, qui pointe vers un serveur HTTP hĂ©bergĂ© sur le port 8445 de localhost !
AprĂšs avoir extrait les chemins et les destinations, le routage suivant peut ĂȘtre observĂ© :

Investigation des services Java
Lors de lâĂ©numĂ©ration des processus, le port 8445 Ă©tait bien rĂ©pertoriĂ© comme un processus Java. Les informations complĂštes sur ce processus sont rĂ©cupĂ©rĂ©es comme suit :
$ lsof -i :8445
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 3301 ftuser 1005u IPv4 50538 0t0 TCP hid:copy (LISTEN)
$ ps -fwwp 3301
UID PID PPID C STIME TTY TIME CMD
ftuser 3301 3247 0 14:19 ? 00:02:29 /usr/java/default/bin/java -server -Xms2048m -Xmx2048m -Dweblogic.Name=ActivIDServer -Djava.security.policy=/opt/hid/weblogic/product/Oracle_Home/wlserver/server/lib/weblogic.policy -Dweblogic.ProductionModeEnabled=true -Djava.system.class.loader=com.oracle.classloader.weblogic.LaunchClassLoader -javaagent:/opt/hid/weblogic/product/Oracle_Home/wlserver/server/lib/debugpatch-agent.jar -da -Dwls.home=/opt/hid/weblogic/product/Oracle_Home/wlserver/server -Dweblogic.home=/opt/hid/weblogic/product/Oracle_Home/wlserver/server -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStore=/opt/hid/weblogic/activid/stores/truststore.jks -Djavax.net.ssl.trustStoreType=JKS -DPWB_CONFIG_FILE=/usr/local/activid/ActivID_AS/config/passphraseObfuscator.properties -Djava.net.preferIPv4Stack=true -Dactivid.home.dir=/usr/local/activid -Djava.awt.headless=true -Djava.library.path=/usr/local/activid/ActivID_AS/lib:/usr/local/lib:/usr/lib:: -Duser.domain=/opt/hid/weblogic/config/activid_domain -Dweblogic.Name=ActivIDServer -Dweblogic.security.SSL.minimumProtocolVersion=TLSv1.2 -Djava.awt.headless=true -Dactivid.enable.monitoring.servlet=true -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 -Dhttps.cipherSuites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA -Dweblogic.Stdout=/opt/hid/weblogic/activid/logs/weblogicStdout.log -Dweblogic.Stderr=/opt/hid/weblogic/activid/logs/weblogicStderr.log -Doracle.dms.context=OFF -DUseSunHttpHandler=true -Djava.security.auth.login.config=/opt/hid/weblogic/config/activid_domain/jaas.conf -Djava.security.egd=file:/dev/./urandom -Dweblogic.security.allowCryptoJDefaultPRNG=true -Djava.security.manager -Dweblogic.MaxMessageSize=41943040 weblogic.Server
Pour résumer, cette commande Java :
- Lance une instance du serveur web WebLogic via la classe
weblogic.Server - Définit certaines de ses propriétés et fonctionnalités (stdin, stdout, utilisation de la mémoire, suites de chiffrement, etc.)
- Configure un domaine situĂ© Ă
/opt/hid/weblogic/config/activid_domain. - Configure certaines variables spécifiques aux applications, par exemple
activid.enable.monitoring.servlet
Pour WebLogic, un domaine nâest rien de moins quâun dossier contenant toutes les ressources nĂ©cessaires pour instancier une ou plusieurs applications Java. Dans un tel dossier, selon la documentation, il devrait y avoir un fichier config.xmlau sein dâun dossier config :
$ ls -lah /opt/hid/weblogic/config/activid_domain/config/config.xml
-rw-rw---- 1 ftadmin ftgroup 12K Sep 2 17:15 /opt/hid/weblogic/config/activid_domain/config/config.xml
Ce fichier XML contient la liste de toutes les applications Java qui ont Ă©tĂ© lancĂ©es au sein du domaine, ainsi que dâautres paramĂštres (port dâĂ©coute, format de journalisation, etc.). Ces applications peuvent, par exemple, ĂȘtre dĂ©ployĂ©es en tant que :
Un WAR (Web Application aRchive) : un fichier dâarchive qui contient une seule application web Java : fichiers HTML statiques, logique mĂ©tier au sein de Servlets, fichiers JSP, librairies Java (extension jar), etc. Une telle application est configurĂ©e par un fichier de configuration, web.xml, situĂ© Ă lâintĂ©rieur du fichier /WEB-INF/web.config, une fois le fichier .war extrait.
Un EAR (Enterprise Application aRchive) : un fichier dâarchive contenant un ou plusieurs fichiers WAR Ă dĂ©ployer, ou dâautres fonctionnalitĂ©s Java telles que les EJBs (Enterprise Java Beans). Ce format est utilisĂ© lorsquâil est nĂ©cessaire de partager du code entre des applications, ou mĂȘme simplement de regrouper un dĂ©ploiement. Une telle application est configurĂ©e par son fichier de configuration /WEB-INF/application.xml, une fois le fichier .ear extrait.
Dans notre cas, la configuration est la suivante :
<server>
<name>ActivIDServer</name>
<ssl>
<name>ActivIDServer</name>
<listen-port>8445</listen-port>
</ssl>
<!-- ... -->
<app-deployment>
<name>4TRESS-EAR</name>
<module-type>ear</module-type>
<source-path>/opt/hid/weblogic/product/Oracle_Home/user_projects/applications/activid_domain/activid-authentication-services-weblogic.ear</source-path>
</app-deployment>
<app-deployment>
<name>ACTIVID-MC</name>
<module-type>war</module-type> <source-path>/opt/hid/weblogic/product/Oracle_Home/user_projects/applications/activid_domain/activid-management-console-weblogic.war</source-path>
</app-deployment>
<app-deployment>
<name>ACTIVID-SSP</name>
<module-type>war</module-type> <source-path>/opt/hid/weblogic/product/Oracle_Home/user_projects/applications/activid_domain/activid-self-service-portal-weblogic.war</source-path>
</app-deployment>
Lâanalyse de ce fichier confirme que lâapplication Java est bien Ă lâĂ©coute sur le port 8445, et surtout donne le chemin dâaccĂšs aux fichiers EAR et WAR dĂ©ployĂ©s, qui contiennent le code Java exĂ©cutĂ© par lâapplication.

Architecture dâune application web Java
Le format EAR
Avant dâentrer dans le code Java, comprenons comment fonctionnent les applications Java. Pour cela, nous allons examiner lâarchitecture de activid-authentication-services-weblogic.ear :
$ unzip activid-authentication-services-weblogic.ear -d activid-authentication-services-weblogic
$ tree ./activid-authentication-services-weblogic/
./activid-authentication-services-weblogic
âââ ac-4tress-core.jar
âââ ac-4tress-scim-configuration.war
âââ ac-4tress-scim.war
âââ ac-iasp-backend.jar
âââ activid-authentication-portal-weblogic.war
âââ activid-health-check.war
âââ lib
â  âââ ac-4tadap-samlproc.jar
â  âââ ac-4tadap-spi.jar
â  âââ ac-4tcore-api.jar
...
â  âââ commons-discovery-0.5.jar
â  âââ commons-fileupload-1.3.3.jar
â  âââ xmlsec-2.2.0.jar
âââ META-INF
âââ application.xml
âââ jboss-deployment-structure.xml
âââ jboss-permissions.xml
âââ MANIFEST.MF
âââ was.policy
âââ weblogic-application.xml
Lorsque vous dĂ©zippez un fichier EAR, vous visualisez une application dâentreprise complĂšte packagĂ©e sous forme de multiples modules. Les fichiers .war sont les applications web (endpoints REST, interfaces utilisateur, servlets), tandis que les fichiers .jar comme ac-4tress-core.jar et ac-iasp-backend.jar sont des modules EJB qui fournissent les services backend utilisĂ©s par ces applications web.
Le rĂ©pertoire lib/ contient les librairies partagĂ©es qui sont visibles par chaque module de lâEAR, permettant de centraliser le code commun au lieu de le dupliquer. Le rĂ©pertoire META-INF/ contient les descripteurs de dĂ©ploiement : weblogic-application.xml pour la configuration spĂ©cifique Ă WebLogic, divers descripteurs de fournisseurs pour dâautres conteneurs, et surtout application.xml, qui dĂ©finit la structure de lâEAR en listant chaque module et en indiquant au serveur dâapplications comment les dĂ©ployer. Ce fichier est le suivant :
<application>
<display-name>ActivID Authentication Services</display-name>
<application-name>4TRESS-EAR</application-name>
<initialize-in-order>true</initialize-in-order>
<module>
<ejb>ac-4tress-core.jar</ejb>
</module>
<module>
<ejb>ac-iasp-backend.jar</ejb>
</module>
<module>
<web>
<web-uri>activid-health-check.war</web-uri>
<context-root>AIHealthCheck</context-root>
</web>
</module>
<module>
<web>
<web-uri>ac-4tress-scim.war</web-uri>
<context-root>scim</context-root>
</web>
</module>
<module>
<web>
<web-uri>ac-4tress-scim-configuration.war</web-uri>
<context-root>configuration</context-root>
</web>
</module>
<module>
<web>
<web-uri>activid-authentication-portal-weblogic.war</web-uri>
<context-root>idp</context-root>
</web>
</module>
</application>
Ici, nous trouvons plusieurs modules web, tels que lâapplication web activid-authentication-portal-weblogic.war. LâĂ©lĂ©ment context-root indique le point de dĂ©part dans lâURL, qui est ici idp. Par consĂ©quent, toute requĂȘte HTTP de la forme http://hid/idp/ sera transmise au WAR associĂ© par WebLogic : activid-authentication-portal-weblogic.war.
AprĂšs avoir examinĂ© ce XML, notre comprĂ©hension de lâapplication et de son architecture est dĂ©sormais la suivante :

Le format WAR
Concernant le format WAR, nous prendrons lâexemple de activID-authentication-portal-weblogic.war :
$ mkdir activid-authentication-portal-weblogic
$ cd activid-authentication-portal-weblogic $ unzip ../activid-authentication-portal-weblogic.war
[...]
$ tree .
.
âââ about.xhtml
âââ auth
â  âââ actions-body.xhtml
â [...]
â  âââ reset-password.xhtmlâââ authn
â  âââ login.xhtml
â  âââ token.xhtml
âââ binding
â  âââ login-artifact.xhtml
â [...]
â  âââ nameid-redirect.xhtml
â  âââ single-logout-post.xhtml
âââ common
â  âââ applet
â  â  âââ applet.xhtml
â  âââ error.xhtml
â  âââ required.xhtml
â [...]
âââ index.html
âââ license.xhtml
âââ META-INF
â  âââ MANIFEST.MF
â  âââ was.policy
âââ nocookie.xhtml
âââ resources
â  âââ csrfguard.js
â  âââ css
â  â  âââ theme.css
â  âââ js
â  âââ base64url-arraybuffer.js
â  âââ webauthn.js
âââ timeout.xhtml
âââ WEB-INF
âââ beans.xml
âââ ejb-jar.xml
âââ jboss-web.xml
âââ lib
â  âââ ac-iasp-frontend.jar
â  âââ ac-iasp-frontend-jaxws.jar
â  âââ ac-inputval-esapi.jar
â  âââ ac-oauth20sdk.jar
â  âââ ai-4tress-samlidp.jar
â  âââ commons-lang3-3.7.jar
â  âââ csrfguard.jar
â  âââ esapi-2.1.0.1.jar
â  âââ lang-tag-1.4.3.jar
â  âââ oauth2-oidc-sdk-5.63.jar
â  âââ primefaces-6.2.jar
âââ weblogic-ejb-jar.xml
âââ weblogic.xml
âââ web.xml
Nous commençons enfin Ă voir des fichiers liĂ©s aux applications web, comme des fichiers HTML (xhtml et html) qui affichent lâinterface utilisateur. Par exemple, naviguer vers la page https://hid/idp/common/error.xhtml affiche :

Cette page correspond correctement au fichier activID-authentication-portal-weblogic/common/error.xhtml que nous venons dâextraire du WAR.
Dans lâarborescence des fichiers, le rĂ©pertoire WEB-INF se distingue. Il contient les fichiers JAR pour toutes les dĂ©pendances locales Ă lâapplication, telles que les classes qui vont gĂ©rer les actions dĂ©clenchĂ©es par les fichiers xhtml ou les requĂȘtes ciblant des Servlets Java web exposĂ©s. Les Servlets Java sont des classes qui exposent des mĂ©thodes accessibles via HTTP, le fondement des applications web Java.
Tandis que le dĂ©clenchement dâun fichier xhtml est direct (puisquâil suffit de connaĂźtre le chemin du fichier et la configuration du module Java Faces), en ce qui concerne les Servlets, nous devons dâabord examiner le fichier web.xml pour comprendre ce qui se passe.
Ce fichier contient beaucoup dâinformations pour cartographier la surface dâattaque, car il dĂ©finit :
Les Servlets, spécifiés dans les balises <servlet>, associés à leur classe Java, ainsi que leur URL définie dans les balises <servlet-mapping>.
Les Filtres (balises <filter>) qui sont appliquĂ©s (Ă comprendre comme des middlewares) avant (requĂȘte HTTP) et aprĂšs (rĂ©ponse HTTP) les actions du servlet, ainsi que les URL pour lesquelles ils sâappliquent (balises <filter-mapping>).
Lâinstanciation des classes et des paramĂštres.
Disséquons celui issu du WAR activID-authentication-portal-weblogic (certaines parties sont tronquées pour plus de clarté) :
$ cat activid-authentication-portal-weblogic/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>ActivID Authentication Portal</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<!-- ... other servlets are declared -->
<servlet>
<description></description>
<display-name>SamlArtResolverServlet</display-name>
<servlet-name>SamlArtResolverServlet</servlet-name>
<servlet-class>com.actividentity.idp.servlet.SamlArtResolverServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SamlArtResolverServlet</servlet-name>
<url-pattern>/binding/artifact-resolution</url-pattern>
</servlet-mapping>
<filter>
<filter-name>ProtocolFilter</filter-name>
<filter-class>javax.faces.webapp.FacesServlet</filter-class>
</filter>
<!-- ... other filters are declared -->
<filter>
<filter-name>SecurityWrapper</filter-name>
<filter-class>com.hidglobal.ia.security.inputval.esapi.SecurityWrapper</filter-class>
</filter>
<filter-mapping>
<filter-name>ProtocolFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ... other filter mappings are declared -->
<filter-mapping>
<filter-name>Security Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<!-- ... -->
</web-app>
Ici, plusieurs Servlets sont dĂ©finis. Par exemple, toute requĂȘte de la forme /idp/binding/artifact-resolution sera transmise au servlet com.actividentity.idp.servlet.SamlArtResolverServlet, car il est rĂ©fĂ©rencĂ© dans le mapping. De la mĂȘme maniĂšre, toute URL correspondant Ă /idp/*.xhtml sera transmise au servlet javax.faces.webapp.FacesServlet.
Cependant, avant dâatteindre ces classes, la requĂȘte HTTP passera par la liste de filtres dĂ©clarĂ©s, si ceux-ci correspondent au filter-mapping. Dans cet exemple, toute requĂȘte (/*) passera par le ProtocolFilter, puis par le Security Filter, dont le code est respectivement dĂ©clarĂ© dans les classes javax.faces.webapp.FacesServlet et com.hidglobal.ia.security.inputval.esapi.SecurityWrapper.
Enfin, pour trouver quelle librairie Java (quel fichier JAR), déclare les classes identifiées, une simple commande grep suffit. Par exemple, avec com.actividentity.idp.servlet.SamlArtResolverServlet :
$ cd activid-authentication-portal-weblogic/WEB-INF/lib/
$ rg -al 'com.actividentity.idp.servlet.SamlArtResolverServlet'
ai-4tress-samlidp.jar
$ unzip -l ai-4tress-samlidp.jar
[...]
2961 2020-12-18 17:10 com/actividentity/idp/servlet/SamlArtResolverServlet.class
Maintenant que nous comprenons comment le fichier web.xml permet de mapper une URL à une classe Java, notre compréhension est désormais la suivante (notez que nous ne détaillons que partiellement la structure du WAR activid-authentication-portal-weblogic précédent) :

Décompilation 101
Ă ce stade, nous sommes dĂ©sormais en mesure de comprendre le routage depuis Nginx jusquâĂ un servlet spĂ©cifique, et donc la classe Java responsable de la logique mĂ©tier. Cependant, nous devons maintenant ĂȘtre capables de lire le code Java afin dâidentifier dâĂ©ventuelles vulnĂ©rabilitĂ©s. Câest lĂ quâintervient la dĂ©compilation.
Plusieurs outils peuvent ĂȘtre utilisĂ©s pour dĂ©compiler le bytecode Java. Au cours de nos recherches, nous avons utilisĂ© [vineflower](https://github.com/Vineflower/vineflower), un dĂ©compilateur Java moderne basĂ© sur le dĂ©compilateur Fernflower de JetBrains.
Pour la décompilation, nous allons cibler les fichiers JAR EJB, ainsi que tous les fichiers JAR situés dans le répertoire lib du fichier WAR extrait :
$ ls -l
-rw-r--r-- 1 user user 3203575 Nov 17 16:08 ac-4tress-core.jar
-rw-r--r-- 1 user user 125721 Nov 17 16:08 ac-iasp-backend.jar
-rw-r--r-- 1 user user 39182 Nov 17 16:06 ac-iasp-frontend.jar
-rw-r--r-- 1 user user 1127763 Nov 17 16:06 ac-iasp-frontend-jaxws.jar
-rw-r--r-- 1 user user 60809 Nov 17 16:06 ac-inputval-esapi.jar
-rw-r--r-- 1 user user 39105 Nov 17 16:06 ac-oauth20sdk.jar
-rw-r--r-- 1 user user 434327 Nov 17 16:06 ai-4tress-samlidp.jar
-rw-r--r-- 1 user user 499634 Nov 17 16:06 commons-lang3-3.7.jar
-rw-r--r-- 1 user user 156911 Nov 17 16:06 csrfguard.jar
-rw-r--r-- 1 user user 395859 Nov 17 16:06 esapi-2.1.0.1.jar
-rw-r--r-- 1 user user 10621 Nov 17 16:06 lang-tag-1.4.3.jar
-rw-r--r-- 1 user user 418019 Nov 17 16:06 oauth2-oidc-sdk-5.63.jar
-rw-r--r-- 1 user user 4271042 Nov 17 16:06 primefaces-6.2.jar
$ fdfind '\.jar$' | parallel java -jar ~/tools/vineflower.jar {} ./out/
[...]
INFO: Decompiling class com/actividentity/service/iasp/frontend/wallet/jaxws/WalletService
INFO: ... done
INFO: Decompiling class com/actividentity/service/iasp/frontend/wallet/jaxws/package-info
[...]
INFO: ... done
Enfin, en utilisant un IDE tel que VSCode, le code Java de SamlArtResolverServlet peut par exemple ĂȘtre lu :

Mise en place du debug
Maintenant que nous avons clarifiĂ© la surface dâattaque et que nous sommes capables de lire le code Java, nous souhaitons ajouter un stub de dĂ©bogage pour pouvoir dĂ©finir des points dâarrĂȘts depuis notre IDE favori pour une analyse plus poussĂ©e.
Lâinspection des processus a rĂ©vĂ©lĂ© que notre application Java a Ă©tĂ© lancĂ©e depuis un processus dont le PID Ă©tait 3315 :
$ ps -fwwp 3315
UID PID PPID C STIME TTY TIME CMD
ftuser 3315 1 0 02:40 ? 00:00:00 /bin/sh /opt/hid/weblogic/config/activid_domain/bin/startWebLogic.sh
$ cat /opt/hid/weblogic/config/activid_domain/bin/startWebLogic.sh
[...]
DOMAIN_HOME="/opt/hid/weblogic/config/activid_domain"
. ${DOMAIN_HOME}/bin/setDomainEnv.sh $*
SAVE_JAVA_OPTIONS="${JAVA_OPTIONS}"
[...]
${JAVA_HOME}/bin/java ${JAVA_VM} ${MEM_ARGS} -Dweblogic.Name=${SERVER_NAME} -Djava.security.policy=${WLS_POLICY_FILE} ${JAVA_OPTIONS} ${PROXY_SETTINGS} ${SERVER_CLASS} >"${WLS_REDIRECT_LOG}" 2>&1
Ce script bash startWebLogic.sh dĂ©finit des variables dâenvironnement et des options qui sont ensuite transmises Ă la commande java. Nous pouvons donc dĂ©tourner ce script afin dâajouter un stub de dĂ©bogage sur notre serveur WebLogic :
JAVA_OPTIONS="${SAVE_JAVA_OPTIONS} -agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n"
En relançant le serveur web, nous pouvons confirmer que le port de notre JDWP est bien en écoute :
$ reboot
$ ss -untalp | grep 5005
tcp LISTEN 0 1 0.0.0.0:5005 0.0.0.0:* users:(("java",pid=3446,fd=628)
Nous avons Ă©galement configurĂ© notre IDE pour sâattacher Ă la JVM distante :

Rapide analyse with CodeQL
Avant de procĂ©der Ă une revue manuelle approfondie, nous passons gĂ©nĂ©ralement le code Ă un outil SAST (Static Application Security Testing). Nous apprĂ©cions particuliĂšrement CodeQL pour le code source Java, car il est gratuit, complet et bien maintenu par la communautĂ©. Il permet dâĂ©crire des requĂȘtes dans un langage basĂ© sur la logique pour trouver des schĂ©mas prĂ©cis : chemins de dĂ©sĂ©rialisation non sĂ©curisĂ©s, concatĂ©nation de chaĂźnes dangereuses dans du SQL, ou tout autre Ă©lĂ©ment qui suit un modĂšle structurel dans le code. Si vous souhaitez plus de dĂ©tails sur lâĂ©criture de vos propres requĂȘtes, nâhĂ©sitez pas Ă consulter la sĂ©rie complĂšte "CodeQL Zero To Hero" sur le blog de CodeQL, ou lâexcellent article de notre expert Hugo Vincent sur la dĂ©couverte dâun gadget de dĂ©sĂ©rialisation JNDI dans Wildfly Ă lâaide de CodeQL.
Création de la base de données
La premiĂšre Ă©tape pour utiliser CodeQL sur un code source donnĂ© est de construire une base de donnĂ©es. Cette base de donnĂ©es contiendra des donnĂ©es interrogeables extraites de votre base de code. Plus prĂ©cisĂ©ment, elle contiendra une reprĂ©sentation complĂšte et hiĂ©rarchique du code, y compris une reprĂ©sentation de lâAST** **(arbre syntaxique abstrait), du DFG (graphe de flux de donnĂ©es) et du CFG (graphe de flux de contrĂŽle). Pour les langages compilĂ©s, lâexĂ©cution dâune analyse SAST implique le plus souvent de compiler le projet en utilisant le code source.
Cela pourrait ĂȘtre problĂ©matique pour nous, car nous ne disposons pas du code source, mais uniquement dâune version dĂ©compilĂ©e qui a Ă©tĂ© extraite des archives de lâapplication identifiĂ©e, et qui ne sera trĂšs probablement pas recompilable.
Cependant, en juin 2025, CodeQL a introduit une nouvelle fonctionnalitĂ© rĂ©volutionnaire appelĂ©e build-mode none. Lâoption build-mode none peut ĂȘtre utilisĂ©e pour crĂ©er des bases de donnĂ©es sans avoir Ă compiler le code source (le support est actuellement limitĂ© Ă C/C++, C#, Java et Rust).
Une fois que nous avons rĂ©ussi Ă extraire les sources de lâapplication, nous avons créé une base de donnĂ©es CodeQL en utilisant la commande suivante :
$ codeql database create ~/codeql/databases/activid-authentication-services-weblogic-8.5 --language java --build-mode none -s activid-authentication-services-weblogic_vineflower/
Note : Lorsque vous travaillez sur de gros projets, il est gĂ©nĂ©ralement judicieux de restreindre lâanalyse aux bibliothĂšques personnalisĂ©es et au code source de votre application. Pour ce faire, il suffit dâĂ©viter de dĂ©compiler les bibliothĂšques tierces avant de crĂ©er votre base de donnĂ©es.
Lancer lâanalyse
LâĂ©tape suivante consiste Ă exĂ©cuter les requĂȘtes CodeQL sur notre base de donnĂ©es fraĂźchement construite.
ExĂ©cuter lâanalyseur CodeQL tel quel, sans arguments supplĂ©mentaires, va dĂ©tecter automatiquement le langage de la base de donnĂ©es et exĂ©cuter les requĂȘtes par dĂ©faut sur la cible, ce qui constitue un bon point de dĂ©part. Cependant, nous aimons gĂ©nĂ©ralement exĂ©cuter des requĂȘtes supplĂ©mentaires, telles que celles provenant de GithubSecurityLab, qui permettent dâidentifier beaucoup plus de problĂšmes de sĂ©curitĂ©.
Pour ce faire, il faut télécharger les packs appropriés :
$ codeql pack download "codeql/java-all@*"
$ codeql pack download "codeql/java-queries@*"
$ codeql pack download "githubsecuritylab/codeql-java-queries"
Ensuite, afin de lancer les requĂȘtes de sĂ©curitĂ© prĂ©-construites qui proviennent des packs que nous venons de tĂ©lĂ©charger, nous pouvons utiliser les suites de requĂȘtes CodeQL. Le fichier suivant, javasec.qls, est créé :
- queries: .
from: codeql/java-queries
- queries: '.'
from: githubsecuritylab/codeql-java-queries
- include:
kind:
- problem
- path-problem
tags contain: security
- exclude:
tags contain:
- debugging
- audit
- template
- exclude:
query path:
- /testing\/.*/
Enfin, nous lançons la suite de requĂȘtes sur la base de donnĂ©es :
$ codeql database analyze ~/codeql/databases/activid-authentication-services-weblogic-8.5/ --format=sarif-latest -o activid-authentication-services-weblogic-8.5.sarif javasec.qls
Ici, nous sĂ©lectionnons le format de sortie SARIF (Static Analysis Results Interchange Format). Comme son nom lâindique, ce format est largement supportĂ© par les outils SAST.
Note : Lâanalyse de la base de donnĂ©es peut ĂȘtre gourmande en ressources. Vous pouvez ajuster les ressources que vous allouez Ă CodeQL en utilisant les options --ram et --threads.
Interprétation des résultats
Lâextension SARIF Viewer peut ensuite ĂȘtre utilisĂ©e pour visualiser les rĂ©sultats :

Bien que certains rĂ©sultats aient semblĂ© prometteurs au dĂ©part, aprĂšs une Ă©tape de vĂ©rification, la plupart des vulnĂ©rabilitĂ©s signalĂ©es ont Ă©tĂ© qualifiĂ©es de faux positifs. Soit parce que nous nâavons trouvĂ© aucun moyen dâatteindre le code mentionnĂ©, soit parce que la donnĂ©e altĂ©rĂ©e Ă©tait assainie avant dâatteindre la fonction dangereuse finale.
Revue manuelle de lâapplication
Cette partie est gĂ©nĂ©ralement trĂšs chronophage. Nous nâentrerons pas dans trop de dĂ©tails ici afin de maintenir la taille de cet article de blog Ă un niveau raisonnable. Il existe essentiellement deux approches qui peuvent ĂȘtre combinĂ©es. La premiĂšre, lâapproche top-down, consiste Ă suivre toutes les routes qui ont Ă©tĂ© identifiĂ©es lors de la phase de dĂ©couverte de la surface dâattaque. La seconde, lâapproche bottom-up, consiste Ă rechercher des fonctions ou des schĂ©mas vulnĂ©rables connus et Ă essayer dâidentifier des chemins qui atteignent ces emplacements, comme nous lâavons fait initialement en utilisant CodeQL. Enfin, les deux approches peuvent ĂȘtre combinĂ©es en une approche hybride en rassemblant autant dâinformations que possible pour tenter de relier les points dâentrĂ©e aux points de sortie, tout en gardant une trĂšs bonne comprĂ©hension du fonctionnement interne de lâapplication. Le dĂ©bogueur peut ĂȘtre dâune grande aide lorsque vous essayez de comprendre comment atteindre une partie spĂ©cifique du code.
Nous avons passĂ© beaucoup de temps sur les endpoints /ssp et /idp, car ces deux points dâaccĂšs sont intensivement utilisĂ©s par les utilisateurs finaux, en particulier lors de lâauthentification.
AprĂšs avoir passĂ© du temps Ă examiner le code sans succĂšs, nous avons dĂ©cidĂ© dâessayer une approche diffĂ©rente et avons commencĂ© Ă interagir dynamiquement avec tous les endpoints que nous avions dĂ©tectĂ©s jusquâĂ prĂ©sent.
Au cours de notre analyse de la surface dâattaque, nous nous sommes souvenus que nous avions identifiĂ© certains endpoints SOAP, mis en Ă©vidence par le nom du fichier de configuration Nginx /etc/nginx/include/app/SoapAPI.conf. Cependant, nous nâavions pas rĂ©ussi Ă interagir avec ceux-ci jusquâĂ prĂ©sent :
# ...
location ^~ /ac-iasp-backend-jaxws/ {
proxy_pass https://$upstream;
limit_except POST {
deny all;
}
if ($request_uri ~* "(?:wsdl|xsd)$") {
return 404;
}
include /etc/nginx/include/soaperrorhandling.conf;
}
AprĂšs quelques recherches sur Google, nous avons rĂ©alisĂ© que JAXWS signifiait Jakarta XML Web Services. Il sâagit dâune mĂ©thode pour exposer des services SOAP en dĂ©finissant des classes Java, câest-Ă -dire de maniĂšre dĂ©clarative. Par exemple, le service UserManager est dĂ©fini comme suit :
File: com/actividentity/service/iasp/backend/bean/UserManagerBean.java
34: @WebService(
35: name = "UserManager",
36: serviceName = "UserService",
37: targetNamespace = "http://jaxws.user.frontend.iasp.service.actividentity.com"
38: )
39: @HandlerChain(
40: file = "/LoginHandlerChain.xml"
41: )
42: @TransactionAttribute(TransactionAttributeType.NEVER)
43: public class UserManagerBean extends ProcessManager implements UserManagerLocal, UserManagerRemote
Comme lâindique la documentation, ce dĂ©corateur WebService devrait crĂ©er un endpoint nommĂ© UserService, et sa documentation WSDL (Web Services Description Language) devrait ĂȘtre accessible Ă lâadresse /ac-iasp-backend-jaxws/UserService?wsdl. Nous avons donc dâabord modifiĂ© la configuration Nginx afin de permettre lâenvoi dâautres verbes HTTP que POST, et de donner accĂšs aux URL se terminant par wsdl ou xsd :
location ^~ /ac-iasp-backend-jaxws/ {
proxy_pass https://$upstream;
include /etc/nginx/include/soaperrorhandling.conf;
}
LâaccĂšs Ă lâendpoint de documentation SOAP UserService nous donne maintenant le rĂ©sultat suivant :

Le fait dâavoir le format WSDL de lâendpoint SOAP nous a permis de lancer lâextension Burp Wsdler, afin dâanalyser le WSDL et le XSD rĂ©fĂ©rencĂ© et dâobtenir des requĂȘtes HTTP prĂ©-construites :

Les requĂȘtes gĂ©nĂ©rĂ©es sont loin dâĂȘtre parfaites, mais lâextension facilite grandement lâensemble du processus de gĂ©nĂ©ration et permet dâinteragir facilement avec les endpoints SOAP. Voici un exemple avec lâendpoint UserManager :

Ă ce stade, seul lâun dâentre nous sâest penchĂ© sur cette partie de lâapplication, et voici ce qui sâest passĂ© :

En effet, sur lâinstance de Vincent, la requĂȘte suivante a fonctionnĂ© :
POST /ac-iasp-backend-jaxws/UserManager HTTP/1.1
SOAPAction:
Content-Type: text/xml;charset=UTF-8
Host: hid:443
Content-Length: 391
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:jax="http://jaxws.user.frontend.iasp.service.actividentity.com">
<soapenv:Header/>
<soapenv:Body>
<jax:findUserIds>
<arg0></arg0>
<!--type: long-->
<arg1>testu7</arg1>
<!--type: long-->
</jax:findUserIds>
</soapenv:Body>
</soapenv:Envelope>
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 09 Sep 2025 17:49:05 GMT
Content-Type: text/xml; charset=utf-8
Connection: keep-alive
X-ORACLE-DMS-ECID: 9eb94a90-9da2-4982-bc84-65fb42ed1688-0000029f
X-ORACLE-DMS-RID: 0
Content-Length: 953
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope
xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns1:findUserIdsResponse
xmlns:ns1="http://jaxws.user.frontend.iasp.service.actividentity.com">
<!-- ... -->
<return>
<id>spl-helpdesk</id>
<type>User</type>
</return>
<return>
<id>spl-stp</id>
<type>User</type>
</return>
<return>
<id>spl-api</id>
<type>User</type>
</return>
<return>
<id>spl-cmsadmin</id>
<type>User</type>
</return>
<return>
<id>sys15188351801401656</id>
<type>User</type>
</return>
<return>
<id>spl-useradmin</id>
<type>User</type>
</return>
</ns1:findUserIdsResponse>
</S:Body>
</S:Envelope>
Alors que du cÎté de Pierre, une erreur serveur 503 est obtenue !
Investigation du comportement suspect
Afin dâinteragir avec les classes Java internes responsables des opĂ©rations mĂ©tier, lâapplication ActivID utilise plusieurs EJB qui sont accessibles via HTTP grĂące Ă JAXWS. Comme nous lâavons vu, ces endpoints sont accessibles via /ac-iasp-backend-jaxws/*.
Analyse de lâauthentification aux services JAXWS
Lâapplication dâauthentification ActivID expose des EJBs via JAXWS en annotant certaines de ses classes avec @WebService.
Par exemple, la classe com.aspace.ftress.interfaces70.ejb.bean.UserManagerBean :
File: com/actividentity/service/iasp/backend/bean/UserManagerBean.java
34: @WebService(
35: name = "UserManager",
36: serviceName = "UserService",
37: targetNamespace = "http://jaxws.user.frontend.iasp.service.actividentity.com" 38: )
39: @HandlerChain(
40: file = "/LoginHandlerChain.xml"
41: )
42: @TransactionAttribute(TransactionAttributeType.NEVER)
43: public class UserManagerBean extends ProcessManager implements UserManagerLocal, UserManagerRemote
Lors de lâaccĂšs Ă lâEJB demandĂ©, JAXWS exĂ©cute dâabord la HandlerChain, qui agit comme un middleware avant dâexĂ©cuter lâendpoint SOAP. Dans ce cas, la HandlerChain pointe vers le fichier LoginHandlerChain.xml, dĂ©fini comme suit :
File: ac-iasp-backend.jar::LoginHandlerChain.xml
1: <?xml version="1.0" encoding="UTF-8"?>
2: <jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee">
3: <!-- Note: The '*" denotes a wildcard. -->
4: <jws:handler-chain name="LoginHandlerChain">
5: <jws:handler>
6: <jws:handler-class>com.actividentity.service.iasp.backend.handler.LoginHandler</jws:handler-class>
7: </jws:handler>
8: </jws:handler-chain>
9: </jws:handler-chains>
Seul un handler est déclaré, com.actividentity.service.iasp.backend.handler.LoginHandler, et il effectue les opérations suivantes :
File: com/actividentity/service/iasp/backend/handler/LoginHandler.java
31: public class LoginHandler implements SOAPHandler<SOAPMessageContext> {
32: private static Logger logger = LogManager.getInstance().getLogger(LoginHandler.class);
33: private static final QName subjectName = new QName("mySubjectUri", "mySubjectHeader"); // [A.4]
[...]
39:
40: public boolean handleMessage(SOAPMessageContext var1) {
41: this.readMessage(var1); // [A.1]
42: return true;
[...]
51:
52: private void readMessage(SOAPMessageContext var1) {
53: logger.debug("LoginHandler: Read SOAP header");
54: Boolean var2 = (Boolean)var1.get("javax.xml.ws.handler.message.outbound");
55: if (!var2) {
56: try {
57: SOAPMessage var3 = var1.getMessage();
58: SOAPEnvelope var4 = var3.getSOAPPart().getEnvelope();
59: SOAPHeader var5 = var4.getHeader();
60: Iterator var6 = var5.examineAllHeaderElements();
61:
62: while (var6.hasNext()) { // [A.2]
63: SOAPHeaderElement var7 = (SOAPHeaderElement)var6.next();
64: if (var7.getElementQName().equals(subjectName)) { // [A.3]
65: logger.debug("LoginHandler: header found, unmarshall it");
66: JAXBElement var8 = jc.createUnmarshaller().unmarshal(var7, MySubject.class); // [A.5]
67: var8.getDeclaredType();
68: MySubject var9 = (MySubject)var8.getValue(); // [A.6]
69: this.setSubject(var9); // [A.7]
70: break;
71: }
72: }
73: } catch (Exception var10) {
74: SubjectHolder.setSubject(null); // [A.8]
75: logger.error("LoginHandler: error getting subject in SOAP header", var10);
76: }
Un tel handler qui implĂ©mente lâinterface SOAPHandler exĂ©cutera la mĂ©thode LoginHandler.handleMessage dĂšs rĂ©ception dâune requĂȘte HTTP SOAP. Dans le cas de ce handler, au niveau de [A.1], la mĂ©thode readMessage est appelĂ©e. Ensuite, Ă [A.2], le code itĂšre sur les Ă©lĂ©ments soapenv:header, et recherche une entrĂ©e ([A.3]) qui correspond Ă mySubjectHeader, lequel est dĂ©fini Ă [A.4]. Puis, il appelle la mĂ©thode com.actividentity.service.iasp.backend.handler.LoginHandler.setSubject Ă [A.7] avec lâobjet subject fourni par lâutilisateur, qui est* unmarshal*Ă© ([A.5]) puis rĂ©cupĂ©rĂ© en [A.6]. Enfin, si une exception est levĂ©e, la mĂ©thode LoginHandler.setSubject est appelĂ©e avec un Subject nul, et la fonction de lâEJB est ensuite exĂ©cutĂ©. La mĂ©thode LoginHandler.setSubject est dĂ©finie comme suit :
File: com/actividentity/service/iasp/backend/handler/LoginHandler.java
080: private void setSubject(MySubject var1) {
081: logger.trace("LoginHandler.setSubject: Begin");
082: Subject var2 = new Subject(); // [B.1]
[...]
092: ChannelCodePrincipal var11 = new ChannelCodePrincipal(var1.getChannel());
093: ALSIPrincipal var12 = new ALSIPrincipal(var1.getUserAlsi()); // [B.2]
[âŠ]
100: var2.getPrincipals().add(var12); // [B.3]
[...]
106: logger.trace("LoginHandler.setSubject: End");
107: SubjectHolder.setSubject(var2); // [B.4]
108: }
Ă [B.1], une instance de javax.security.auth.Subject est créée Ă partir de lâinstance MySubject fournie. Ensuite, Ă [B.2], la valeur ALSI fournie par lâutilisateur est rĂ©cupĂ©rĂ©e, puis dĂ©finie sur lâinstance Subject.
Cette valeur ALSI imprĂ©visible est utilisĂ©e par lâapplication comme session stockĂ©e cĂŽtĂ© serveur.
En [B.3], la méthode statique SubjectHolder.setSubject est appelée :
File: com/actividentity/service/iasp/util/security/SubjectHolder.java
01: package com.actividentity.service.iasp.util.security;
02:
03: import javax.security.auth.Subject;
04:
05: public class SubjectHolder {
06: static ThreadLocal<Subject> subject = new ThreadLocal<>(); // [C.2]
07:
08: publi