{"id":604,"date":"2017-08-17T12:09:13","date_gmt":"2017-08-17T10:09:13","guid":{"rendered":"http:\/\/www.loicmathieu.fr\/wordpress\/?p=604"},"modified":"2017-08-17T12:13:44","modified_gmt":"2017-08-17T10:13:44","slug":"kerberos-authentification-avec-springsecurity","status":"publish","type":"post","link":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/kerberos-authentification-avec-springsecurity\/","title":{"rendered":"Authentification Kerberos avec SpringSecurity"},"content":{"rendered":"<p><\/p>\n<h2>Introduction<\/h2>\n<p>J&#8217;ai r\u00e9cemment impl\u00e9ment\u00e9 une authentification (automatique) avec Kerberos. Ce protocole permet d&#8217;authentifier automatiquement un utilisateur depuis sa session utilisateur (session windows par exemple). Via Kerberos, on authentifie donc un utilisateur sans lui demander son mot de passe ce qui est un plus (il n&#8217;a pas \u00e0 se re-logguer : on utilise le contexte d&#8217;authentification de Windows) en se basant sur le fait que s&#8217;il a ouvert une session utilisateur en son nom &#8230; alors tout est OK!<\/p>\n<p>En impl\u00e9mentant \u00e7a, j&#8217;ai eu pas mal de soucis dont j&#8217;ai eu du mal \u00e0 trouver des solutions dans les ressources disponibles aujourd&#8217;hui, d&#8217;o\u00f9 l&#8217;id\u00e9e de ce petit article.<\/p>\n<p><em><strong>Attention : je ne suis pas expert Kerberos, donc certains termes\/certaines assertions ne sont peut \u00eatre pas correcte, j&#8217;exprime ici la mani\u00e8re dont j&#8217;en ai compris le fonctionnement.<\/strong><\/em><\/p>\n<h2>Comment marche Kerberos :<\/h2>\n<p>Kerberos expliqu\u00e9 \u00e0 un enfant de 5 ans (en anglais) : <a href=\"http:\/\/www.roguelynn.com\/words\/explain-like-im-5-kerberos\" target=\"_blank\">http:\/\/www.roguelynn.com\/words\/explain-like-im-5-kerberos<\/a>\/<\/p>\n<p>R\u00e9sum\u00e9 en quelques lignes : Kerberos est un protocol d&#8217;authentification par ticket:  le ticket est g\u00e9n\u00e9r\u00e9 par un syst\u00e8me tiers (le KDC &#8211; Key Distribution Center), inject\u00e9 dans un header HTTP, lut par votre navigateur. Ce ticket peut ensuite \u00eatre utilis\u00e9 par votre application qui va le faire valider par le KDC et peut ensuite s&#8217;assurer de la validit\u00e9e de l&#8217;authentification en r\u00e9cup\u00e9rant le contexte d&#8217;authentification de votre session utilisateur (votre nom d&#8217;utilisateur entre autre) depuis ce ticket.<\/p>\n<h2>Impl\u00e9mentation avec Spring Security kerberos<\/h2>\n<p>Site du projet : <a href=\"http:\/\/projects.spring.io\/spring-security-kerberos\/\" target=\"_blank\"><a href=\"http:\/\/projects.spring.io\/spring-security-kerberos\/\">http:\/\/projects.spring.io\/spring-security-kerberos\/<\/a><\/a><\/p>\n<h3>Configuration de la s\u00e9curit\u00e9<\/h3>\n<p>Pour commencer, vous avez besoin de deux composants permettant d&#8217;initier une n\u00e9gociation Kerberos, et de configurer ceux-ci dans la configuration Spring Security. Un exemple ici en Spring Config : <\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Configuration\n@EnableWebMvcSecurity\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {\n        @Autowired private AuthenticationManager authenticationManager;\n\n        \/**\n     * cr\u00e9\u00e9 un bean SpnegoAuthenticationProcessingFilter (filtre de n\u00e9gociation Kerberos)\n     * @return\n     *\/\n    @Bean\n    public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter() {\n        SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();\n        filter.setAuthenticationManager(this.authenticationManager);\n        return filter;\n    }\n\n    \/**\n     * cr\u00e9\u00e9 un bean SpnegoEntryPoint (point d'entr\u00e9 de la n\u00e9gociation Kerberos)\n     * @return\n     *\/\n    @Bean\n    public SpnegoEntryPoint spnegoEntryPoint() {\n        return new SpnegoEntryPoint(\"\/login\");\n    }\n\n    \/**\n     * @inheritDoc\n     *\/\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        \/\/configuration Kerberos\n        http.exceptionHandling().authenticationEntryPoint(spnegoEntryPoint());\n        http.addFilterBefore(spnegoAuthenticationProcessingFilter(), BasicAuthenticationFilter.class);\n        \/\/... autre conf ...\n    }\n}\n<\/pre>\n<p>Ceci permettra, sur la page de login (ici \/login) de d\u00e9clencher une n\u00e9gociation Kerberos. Le navigateur va alors lire le ticket Kerberos et le mettre \u00e0 disposition pour le service d&#8217;authentification Kerberos.<\/p>\n<h3>Configuration Kerberos<\/h3>\n<p>Pour le ticket Kerberos soit valid\u00e9, il faut fournir un ensemble de configuration, c&#8217;est l\u00e0 que c&#8217;est le plus compliqu\u00e9 et le plus sp\u00e9cifique \u00e0 votre configuration Kerberos. Il vous faudra l&#8217;aide de vos administrateur du KDC (Key Distribution Center : vos administrateur Microsoft Active Directory pour une session windows) pour avoir un keytab et un krb5.ini. Ceux-ci permettent de faire le lien entre votre application et le KDC. <\/p>\n<p>Pour vous aider \u00e0 vous retrouver dans tous \u00e7a :<\/p>\n<ul><li>Le service principal doit \u00eatre de la forme : <strong>HTTP\/hostname@realm<\/strong> : exemple HTTP\/myhost.exemple.com@PC.EXEMPLE.COM. Attention, le hostname doit \u00eatre celui utilis\u00e9 dans le navigateur pour acc\u00e9der \u00e0 votre application.<\/li>\n\n<li><strong>Le keytab doit \u00eatre g\u00e9n\u00e9r\u00e9 pour le service principal que vous utilisez<\/strong>, il permet \u00e0 l&#8217;host de votre application de s&#8217;authentifier aupr\u00e8s du KDC<\/li>\n\n<li><strong>Votre krb5.ini doit contenir le realm utilis\u00e9 et le lien entre celui-ci et le KDC<\/strong> (un exemple plus bas), il permet \u00e0 votre application de savoir o\u00f9 se situe le KDC<\/li>\n<\/ul>\n<p>Une fois que vous avez tous ceci, il vous faut configurer Kerberos, voici un petit exemple via Spring Config :<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Configuration\npublic class KerberosConfiguration {\n    @Resource private UserDetailsService userDetailsService;\/\/votre UserDetailService permettant de charger votre utilisateur via son userName\n    @Value(\"${kerberos.service_principal}\") private String servicePrincipal;\n    @Value(\"${kerberos.keytab_location}\") private String keytabLocation;\n    @Value(\"${kerberos.krb5_ini}\") private String krb5iniLocation;\n\n    \/**\n     * cr\u00e9\u00e9 un bean KerberosServiceAuthenticationProvider pour l'authentification Kerberos\n     * @return\n     *\/\n    @Bean\n    public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {\n        KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();\n        provider.setTicketValidator(sunJaasKerberosTicketValidator());\n        provider.setUserDetailsService(this.userDetailsService);\n        return provider;\n    }\n\n    \/**\n     * cr\u00e9\u00e9 un bean de type SunJaasKerberosTicketValidator : c'est lui qui validera le ticket Kerberos (le header)\n     * @return\n     *\/\n    @Bean\n    public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {\n        System.setProperty(\"java.security.krb5.conf\", krb5iniLocation);\n        SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();\n        ticketValidator.setServicePrincipal(servicePrincipal);\n        ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation));\n        return ticketValidator;\n    }\n}\n<\/pre>\n<p>Et voici un exemple de krb5.ini :<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n[libdefaults]\n dns_lookup_realm = true\n ticket_lifetime = 24h\n renew_lifetime = 7d\n forwardable = true\n rdns = false\n default_realm = PC.EXEMPLE.COM\n default_ccache_name = KEYRING:persistent:%{uid}\n permitted_enctypes = aes128-cts aes256-cts arcfour-hmac-md5\n\n[realms]\nPC.EXEMPLE.COM = {\n        kdc = MYKDC.PC.EXEMPLE.COM\n        admin_server = MYKDC.PC.EXEMPLE.COM\n        default_domain = PC.EXEMPLE.COM\n}\n\n[domain_realm]\n.pc.exemple.com = PC.EXEMPLE.COM\npc.exemple.com = PC.EXEMPLE.COM\n\n[logging]\n    kdc = FILE:\/var\/log\/krb5\/krb5kdc.log\n    admin_server = FILE:\/var\/log\/krb5\/kadmind.log\n    default = SYSLOG:NOTICE:DAEMON\n\n<\/pre>\n<h3>Votre user service<\/h3>\n<p>Gr\u00e2ce \u00e0 kerberos, le navigateur va directement passer le contexte d&#8217;authentification de votre session Windows au KDC qui le validera. Ensuite, vous aurez une authentification Spring Security valide &#8230; mais sans autres informations sur votre utilisateur que son login Windows.<\/p>\n<p>Pour aller plus loin, il vous faudra impl\u00e9menter votre propre UserDetailService qui ira, depuis le login de l&#8217;utilisateur, charger l&#8217;utilisateur depuis l&#8217;AD\n\/un LDAP\/ une base. A vous de voir en fonction de l&#8217;endroit o\u00f9 vous stockez les informations de l&#8217;utilisateur, et surtout, ses droits!\n\n<\/p>\n<p>Avec Kerberos, l&#8217;int\u00e9gration d&#8217;un load balancer se trouve compliqu\u00e9. En effet, la n\u00e9gociation Kerberos s&#8217;effectue depuis le navigateur et depuis le host de votre application. Si l&#8217;URL de votre application est http:\/\/loadbalancer.exemple.com et que vos hosts sont host1.exemple.com et host2.exemple.com alors vous aurez un ticket Kerberos sur un principal HTTP\/loadbalancer.exemple.com@PC.EXEMPLE.COM et pas un ticket sur le principal HTTP\/host1.exemple.com@PC.EXEMPLE.COM.<\/p>\n<p>Pour r\u00e9soudre ce probl\u00e8me, il faut sur chaque host derri\u00e8re le loadbalancer utiliser le m\u00eame principal et le m\u00eame keytab qui sont celui du loadbalancer et pas celui de l&#8217;host. C&#8217;est la seule mani\u00e8re que j&#8217;ai trouv\u00e9 de contourner le probl\u00e8me (m\u00eame si certain articles expliquent qu&#8217;il faut g\u00e9n\u00e9rer un keytab avec deux principal : un pour l&#8217;host et un pour le loadbalancer je n&#8217;ai pas r\u00e9ussit \u00e0 faire fonctionner cette configuration)\u00e0.<\/p>\n<p>Voici deux articles sur le sujet :<\/p>\n<ul><li>https:\/\/ssimo.org\/blog\/id_019.html<\/li>\n\n<li>https:\/\/devcentral.f5.com\/questions\/apm-how-to-create-a-keytab-file-with-multiple-spns<\/li>\n<\/ul>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>Introduction J&#8217;ai r\u00e9cemment impl\u00e9ment\u00e9 une authentification (automatique) avec Kerberos. Ce protocole permet d&#8217;authentifier automatiquement un utilisateur depuis sa session utilisateur (session windows par exemple). Via Kerberos, on authentifie donc un utilisateur sans lui demander son mot de passe ce qui est un plus (il n&#8217;a pas \u00e0 se re-logguer : on utilise le contexte d&#8217;authentification de Windows) en se basant sur le fait que s&#8217;il a ouvert une session utilisateur en son nom &#8230; alors tout est OK! En impl\u00e9mentant&#8230;<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/kerberos-authentification-avec-springsecurity\/\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[9],"tags":[],"class_list":["post-604","post","type-post","status-publish","format-standard","hentry","category-informatique"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":827,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/devfest-lille-2018\/","url_meta":{"origin":604,"position":0},"title":"Devfest Lille 2018","author":"admin","date":"Friday July  6th, 2018","format":false,"excerpt":"gRPC ----- - Rappel r\u00e9seau, internet - Probl\u00e9matique du format de donn\u00e9e dans les systeme distribu\u00e9 => modification difficile - Historique des protocoles RCP : CORBA, RMI, EJB, SOAP, REST -> 2008 Protocol Buffers : s\u00e9rialization (pr\u00e9mice du RCP chez Google : open sourcing partiel) -> 2009 Thrift (Fb) ->\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1330,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/devoxx-france-2021-ledition-9-3-4\/","url_meta":{"origin":604,"position":1},"title":"(Fran\u00e7ais) Devoxx France 2021 &#8211; l&#8217;\u00e9dition 9 3\/4","author":"admin","date":"Friday October  1st, 2021","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":40,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/integration-continue\/","url_meta":{"origin":604,"position":2},"title":"Int\u00e9gration Continue avec Cruise Control","author":"admin","date":"Wednesday November 14th, 2007","format":false,"excerpt":"Derni\u00e8rement, j'ai essay\u00e9 un serveur d'int\u00e9gration continue : Cruise Control. Je vais donc vous en parler ici. Tout d'abord, qu'est-ce que l'int\u00e9gration continue: L'int\u00e9gration continue est une technique de d\u00e9veloppement\/management de projet qui implique d'int\u00e9grer tr\u00e8s fr\u00e9quemment le travail de tout les membres. Ensuite, une compilation automatique doit \u00eatre lanc\u00e9\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1258,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/profiler-une-application-java-dans-un-conteneur-deploye-dans-kubernetes-avec-jfr-java-flight-recorder\/","url_meta":{"origin":604,"position":3},"title":"(Fran\u00e7ais) Profiler une application Java dans un conteneur d\u00e9ploy\u00e9 dans kubernetes avec JFR &#8211; Java Flight Recorder","author":"admin","date":"Monday April 12th, 2021","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":391,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/chti-jug-drools-v5-et-drools-planner\/","url_meta":{"origin":604,"position":4},"title":"Ch&#8217;ti Jug: Drools v5 et Drools Planner","author":"admin","date":"Saturday February 13th, 2010","format":false,"excerpt":"Jeudi 21 janvier s'est tenu dans les locaux de l'Universit\u00e9 de Lille 1 une session du Ch'ti Jug sponsoris\u00e9e par Cylande sur Drools:\u00a0 Drools, avec Cylande et l'Universit\u00e9 Lille 1 Pour ceux qui ne savent pas ce qu'est le Ch'ti Jug ou ce qu'est un Jug, voir l'introduction de mon\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":966,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/1-an-chez-zenika\/","url_meta":{"origin":604,"position":5},"title":"(Fran\u00e7ais) 1 an chez Zenika","author":"admin","date":"Tuesday September  3rd, 2019","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/604","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/comments?post=604"}],"version-history":[{"count":0,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/604\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/media?parent=604"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/categories?post=604"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/tags?post=604"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}