Intégrer Alfresco à un système d’authentification unique (SSO) a toujours été un sujet complexe à aborder. C’est un sujet qui revient à chaque nouveau déploiement d’Alfresco chez nos clients et il n’y a pas de réponse toute prête à apporter :
Le but est d’arriver à faire correspondre les attentes du client en terme d’authentification (prendre en compte l’existant et la cible à atteindre), les possibilités offertes par Alfresco et les contraintes techniques. Et tout ceci en conservant un bon niveau de sécurité.
Dans ce billet, nous allons aborder le mécanisme de SSO «External authentication
» proposé par Alfresco. C’est le plus simple à comprendre et il est facile à mettre en place. C’est également l’occasion de donner une suite àun billet de blog écrit il y a plus de 10 ans sur le même sujet. À l’époque le sujet concernait la mise en place d’un SSO entre Alfresco Explorer et Share via l’utilisation de CAS. Nous allons voir que l’intégration de CAS est maintenant grandement facilitée.
Cette introduction étant déjà bien trop longue, commençons tout de suite avec une rapide présentation du «External authentication
».
Ce billet n’a pas pour but de remplacer la documentation officielle, je vous invite donc à la lire en complément de ce billet. Toutefois, ne vous laissez pas influencer par la documentation, celle-ci fait souvent référence à CAS mais le système «External authentication
» n’est pas lié à un mécanisme de SSO particulier. Et c’est d’ailleurs là tout son intérêt et sa simplicité :
External», ce n’est plus Alfresco qui gère l’authentification, mais un élément externe)
Le mécanisme «External authentication
» ne présuppose en aucun cas de la méthode utilisée pour authentifier l’utilisateur. Le seul pré-requis concerne la présence de l’en-tête HTTP contenant le login de l’utilisateur. Le nom de cet en-tête est configurable côté Alfresco, vous pouvez utilisez n’importe quelle valeur (dans la suite de ce billet, nous utiliseronsX-Alfresco-Remote-User
). La valeur de l’en-tête doit contenir uniquement le login de l’utilisateur, tel que connu par Alfresco. Les comptes étant créés généralement via une synchronisation avec un annuaire LDAP, il faut bien s’assurer que le contenu de l’en-tête correspond au login remonté par la synchronisation LDAP.
Et c’est tout ce qu’il faut savoir sur cette méthode d’authentification.
Point important à noter : il s’agit d’un mécanisme d’authentification qui fonctionne uniquement en HTTP. N’espérez pas le faire fonctionner avec d’autres protocoles comme CIFS ou FTP.
Vous avez certainement remarqué la présence du proxy authentifiant sur le schéma juste au-dessus. Il s’agit de la brique réalisant l’authentification des utilisateurs. Le mécanisme utilisé pour authentifier les utilisateurs n’a aucune incidence sur la partie Alfresco ou Share, du moment que l’en-tête est bien présent avec la bonne valeur. Et vous êtes libre d’utiliser ce que vous voulez à ce niveau.
Concrètement, tous les modules d’authentification gérés par Apache HTTPD sont possibles :CAS bien sûr, mais égalementSAML,Kerberos ouOpenID Connect. On peut même envisager de l’authentification àdeux facteurs (plus connu sous le nom 2FA) et de l’authentification via certificat.
Si vous préférez Nginx, ne partez pas, il y a tout ce qu’il faut (ou presque) :CAS,OpenID Connect,Kerberos,certificat , etc.
Il est également possible d’utiliser des solutions plus complètes du typeLemonLDAP::NG. Configuré en tant que reverse-proxy authentifiant devant les applications Alfresco et Share, vous aurez alors accès à unnombre impressionnant de backends pour réaliser l’authentification.
Bref, le choix ne manque pas et vous trouverez certainement votre bonheur avec tous ces modules d’authentification.
Côté serveur Alfresco, il y a 3 éléments à configurer :
Ces trois points de configuration seront toujours les mêmes quelque soit le mécanisme utilisé au niveau du proxy authentifiant. À noter que les exemples de configuration concernent Alfresco 6.2. Il faudra les adapter pour les autres versions d’Alfresco.
Il faut indiquer à Tomcat de propager l’authentification provenant du proxy authentifiant vers les applications. Ceci est valable uniquement si vous utilisez leconnecteur AJP entre le proxy authentifiant et Tomcat. Si vous passez par le connecteur HTTP ou HTTPS, cette étape n’est pas nécessaire.
conf/server.xml
tomcatAuthentication=false
au connecteur AJP :1 2 3 4 | <!-- Define an AJP 1.3 Connector on port 8009 --> <Connectorport="8009"protocol="AJP/1.3"redirectPort="8443" URIEncoding="UTF-8" tomcatAuthentication="false" /> |
Il faut ajouter un nouveau type d’authentification (de typeexternal
) dans votrechaîne d’authentification.
shared/classes/alfresco-global.properties
authentication.chain
pour lui ajouter une authentification de typeexternal
1 | authentication.chain=cas:external,alfrescoNtlm1:alfrescoNtlm |
external
1 2 3 4 | external.authentication.enabled=true external.authentication.defaultAdministratorUserNames=admin external.authentication.proxyUserName= external.authentication.proxyHeader=X-Alfresco-Remote-User |
Vous l’aurez compris, le paramètreexternal.authentication.proxyHeader
doit correspondre au nom de l’en-tête envoyé par le proxy authentifiant.
La configuration de Share passe par la création de fichiers XML à placer dans le dossiershared/classes/alfresco/web-extension/
.
external-auth-context.xml
avec le contenu suivant :1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xmlversion='1.0'encoding='UTF-8'?> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'> <beans> <beanid="external.auth.config"class="org.springframework.extensions.config.ConfigBootstrap"init-method="register"> <propertyname="configService"ref="web.config" /> <propertyname="configs"> <list> <value>classpath:alfresco/web-extension/external-auth-config.xml</value> </list> </property> </bean> </beans> |
external-auth-config.xml
avec le contenu suivant :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <alfresco-config> <configevaluator="string-compare"condition="Remote"> <remote> <connector> <id>alfrescoCookie</id> <name>Alfresco Connector</name> <description>Connects to an Alfresco instance using cookie-based authentication</description> <class>org.alfresco.web.site.servlet.SlingshotAlfrescoConnector</class> </connector> <connector> <id>alfrescoHeader</id> <name>Alfresco Connector</name> <description>Connects to an Alfresco instance using header and cookie-based authentication</description> <class>org.alfresco.web.site.servlet.SlingshotAlfrescoConnector</class> <userHeader>X-Alfresco-Remote-User</userHeader> </connector> <endpoint> <id>alfresco</id> <name>Alfresco - user access</name> <description>Access to Alfresco Repository WebScripts that require user authentication</description> <connector-id>alfrescoHeader</connector-id> <endpoint-url>http://localhost:8080/alfresco/wcs</endpoint-url> <identity>user</identity> <external-auth>true</external-auth> </endpoint> <endpoint> <id>alfresco-feed</id> <parent-id>alfresco</parent-id> <name>Alfresco Feed</name> <description>Alfresco Feed - supports basic HTTP authentication via the EndPointProxyServlet</description> <connector-id>alfrescoHeader</connector-id> <endpoint-url>http://localhost:8080/alfresco/wcs</endpoint-url> <identity>user</identity> <external-auth>true</external-auth> </endpoint> <endpoint> <id>alfresco-api</id> <parent-id>alfresco</parent-id> <name>Alfresco Public API - user access</name> <description>Access to Alfresco Repository Public API that require user authentication. This makes use of the authentication that is provided by parent 'alfresco' endpoint.</description> <connector-id>alfrescoHeader</connector-id> <endpoint-url>http://localhost:8080/alfresco/api</endpoint-url> <identity>user</identity> <external-auth>true</external-auth> </endpoint> </remote> </config> </alfresco-config> |
N’oubliez pas de modifier la baliseuserHeader
avec la nom de l’en-tête envoyé par le proxy authentifiant.
Rien de plus simple, une simple commandecurl
en vous assurant de passer l’en-tête attendu par Alfresco :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [root@acs62~]#curl -sv -o/dev/null -H"X-Alfresco-Remote-User: admin"http://localhost:8080/alfresco/wcs/enterprise/admin/admin-systemsummary >GET/alfresco/wcs/enterprise/admin/admin-systemsummaryHTTP/1.1 >User-Agent:curl/7.29.0 >Host:localhost:8080 >Accept:*/* >X-Alfresco-Remote-User:admin > <HTTP/1.1200OK <Server:Apache-Coyote/1.1 <Set-Cookie:JSESSIONID=63BBE29F27CEFD2A277518F6163462E8;Path=/alfresco;HttpOnly <Set-Cookie:alf-csrftoken=rNRl0bLNABnBqsnfvFHaepeX4sxO%2bbkbhf8CIPtQ158%3d;Expires=Tue,21-Apr-202012:58:01GMT;Path=/alfresco <Cache-Control:no-cache <Expires:Thu,01Jan197000:00:00GMT <Pragma:no-cache <Content-Type:text/html;charset=UTF-8 <Transfer-Encoding:chunked <Date:Tue,14Apr202012:58:04GMT |
Alfresco répond avec un code200 OK
, tout va bien, on a été authentifié et l’accès à la console d’administration est autorisé. Un code401 Unauthorized
aurait indiqué un échec d’authentification et donc un souci dans la configuration d’Alfresco.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [root@acs62~]#curl -sv -o/dev/null -H"X-Alfresco-Remote-User: admin"http://localhost:8080/share/page/ >GET/share/page/HTTP/1.1 >User-Agent:curl/7.29.0 >Host:localhost:8080 >Accept:*/* >X-Alfresco-Remote-User:admin > <HTTP/1.1302Found <Server:Apache-Coyote/1.1 <Set-Cookie:JSESSIONID=40A1908D6D013644798E1978F35B1BEA;Path=/share;HttpOnly <Set-Cookie:Alfresco-CSRFToken=W5ElnBa6rM%2bXiP513eW7yr9g23Xlpo1trexNdoDwnhA%3d;Expires=Tue,21-Apr-202013:01:58GMT;Path=/share <X-Frame-Options:SAMEORIGIN <X-Content-Type-Options:nosniff <X-XSS-Protection:1;mode=block <Cache-Control:no-cache <Location:/share/page/user/admin/dashboard <Content-Type:text/html;charset=utf-8 <Content-Language:en-US <Content-Length:0 <Date:Tue,14Apr202013:01:57GMT |
L’authentification a également fonctionné avec Share : nous obtenons une redirection302 Found
vers le tableau de bord de l’utilisateuradmin
(voir l’en-tête HTTPLocation
dans la réponse). En cas d’échec d’authentification, la redirection aurait été faite vers le formulaire d’authentificationLocation: /share/page?pt=login
).
Bonne remarque ! Comme souvent avec les composants qui touchent à la sécurité et à l’authentification, il ne faut pas juste s’arrêter à «Ça fonctionne, je ne touche plus à rien »
. Il est important de bien comprendre ce que nous venons de faire.
Comme vous l’avez certainement compris, Alfresco fait totalement confiance à la valeur de l’en-tête pour authentifier l’utilisateur. Il faut donc faire en sorte que l’en-tête arrivant au niveau d’Alfresco soit digne de confiance. Il est très facile pour un attaquant de forger un en-tête malveillant et ainsi se faire passer pour n’importe quel autre utilisateur. Il n’est pas nécessaire de connaitre toutes les options de la commandecurl
pour y arriver, il existe des extensions pour nos navigateurs préférés dont le but est de créer et/ou modifier les en-têtes HTTP (par exempleModify Header Value pour Firefox).
Les bonnes pratiques à respecter :
X-Alfresco-Remote-User
des requêtes entrantesPour le premier point, il est possible de mettre en place des règles de filtrage du trafic entrant avec l’utilisation d’un firewall directement sur le serveur Alfresco, ou via leRemote Address Filter de Tomcat. Uniquement le proxy authentifiant doit être autorisé à accéder à Tomcat. Cependant, ceci ne vous protégera pas des attaques locales (si l’attaquant à accès au serveur, il shunte toutes ces protections).
Pour le second point, cela dépend du proxy authentifiant utilisé. Par exemple avec Apache HTTPD, il est possible de supprimer l’en-tête des requêtes entrantes avec la directiveRequestHeader
suivante :
1 | RequestHeaderunset"X-Alfresco-Remote-User"early |
Pour aller plus loin, il est également possible de mettre en place un mécanisme d’authentification mutuelle en TLS entre le proxy authentifiant et Tomcat. Le proxy authentifiant se connecte en TLS et présente un certificat client à Tomcat, celui-ci est configuré pour valider le certificat présenté. Alfresco va ensuite vérifier que ce certificat correspond à l’utilisateur indiqué par le paramètreexternal.authentication.proxyUserName
(ce même paramètre que nous avions laissé vide dans l’exemple de configuration d’Alfresco ci-dessus). Si tout est ok, la requête continue son chemin et Alfresco utilise toujours l’en-tête HTTP pour authentifier l’utilisateur.
L’utilisation d’un certificat client permet une authentification mutuelle entre le proxy authentifiant et Tomcat. Il est ainsi possible d’établir une relation de confiance entre ces deux applications et de garantir l’authenticité de l’en-tête HTTP. Sans le certificat client, pas d’accès possible à Tomcat.
Si mon explication est suffisamment claire, et si vous connaissez un peu Alfresco, vous aurez remarqué qu’il s’agit du même principe déjà utiliséentre Alfresco et Solr (même si la mise en œuvre est différente, le principe reste identique).
Depuis le début de l’article, je pars du principe que nous souhaitons authentifier un utilisateur dans un contexte purement web (en HTTP) et souhaitant accéder à l’interface Share. Cependant Alfresco propose bien plus de services que l’interface Share : Webdav, différentes API (REST, CMIS), l’édition en ligne avec MS Office (AOS), etc. Ces différents services reposent généralement sur leur propre mécanisme d’authentification, et il est rare que le mécanisme d’authentification mis en place au niveau du proxy authentifiant soit utilisable directement.
Comme exemple parlant, prenons le cas de l’accès au partage Webdav d’Alfresco avec une authentification CAS au niveau du proxy authentifiant. À ma connaissance, aucun client Webdav ne sait gérer l’authentification CAS. Sans action particulière, il ne sera plus possible d’utiliser l’accès Webdav via le proxy authentifiant.
Autre exemple : Share offre la possibilité de créer un lien public vers un document. Toutes les personnes connaissant ce lien peuvent avoir accès au document sans authentification ni compte dans Alfresco … sauf que le proxy authentifiant va jouer son rôle et va imposer une authentification, même pour accéder à une ressource considérée comme publique au niveau de Share.
Pour retrouver le comportement standard d’Alfresco et de Share il sera nécessaire de configurer le proxy authentifiant pour ajouter des exceptions. Le but est de laisser passer certaines URL sans nécessité d’avoir un utilisateur authentifié. Cette configuration étant réalisée au niveau du proxy authentifiant, on déborde du périmètre de billet et sa mise en place est laissé comme exercice au lecteur (ce billet étant déjà bien trop long).
Bonjour,
Merci beaucoup pour ce tutoriel intéressant.
J’ai suivi toutes les étapes et ça marche bien avec ma configuration locale, par contre en volant faire la même chose avec un vrai serveur LemonLdap je tombe sur des erreur causé par le fait de recevoir l’identifiant chiffré en base64.
Authorization: base xxxxx
Avez-vous une idée de comment indiquer à Alfresco qu’il va recevoir l’identifiant en base64 et pas en clair.
Merci d’avance de me répondre, ça fait plusieurs semaines que je suis bloqué sur ce sujet.
Bonjour Yazid,
Avec un Alfresco standard, il s’attend à recevoir le login dans un header HTTP, et il faut que ce login ne soit pas transformé. Ce qui exclue donc tout ce qui est transformation en base64, ou chiffrement/signature ou tout autre méthode qui altérerait ce login.
Trois pistes envisageables (il en existe sûrement d’autres…) :
– modifier la configuration de LemonLdap pour envoyer le login sans modification
– ajouter un intermédiaire qui décode le base64 et ré-injecte le login décodé dans un autre header HTTP
– faire un petit développement spécifique dans Alfresco pour décoder le login au format base64
Laurent
Bonjour,
j’utilise alfresco 7, et j’essaye de mettre en place un websso OIDC Apache en frontal d’alfresco. Tout fonctionne nickel, sauf que l’appel alfresco/api/-default-/public/authentication/versions/1/tickets me renvoie un 405.
Je n’arrive pas à récupérer le ticket. Alors que je suis bien authentifié selon alfresco.
avez vous une idée ?
merci par avance,
Bonjour Christophe,
La réponse 405 Method Not Allowed indique que l’url alfresco/api/-default-/public/authentication/versions/1/tickets n’est pas appelée correctement.
La documentation (https://docs.alfresco.com/content-services/latest/develop/rest-api-guide/install/#authenticating-to-get-a-ticket) décrit comment cette URL doit être exploitée pour obtenir un ticket. Elle n’a par ailleurs pas de lien avec l’authentification externe.
Damien
Ce site utilise Akismet pour réduire les indésirables.En savoir plus sur la façon dont les données de vos commentaires sont traitées.
Sorry, no Tweets were found.
© 2025Atol Open Blog — Powered byWordPress
Theme byAnders Noren —Up ↑