{"id":29,"date":"2007-08-07T20:43:00","date_gmt":"2007-08-07T19:43:00","guid":{"rendered":"http:\/\/euve3303.vserver.de\/stefan\/blog\/?p=31"},"modified":"2011-12-02T21:23:55","modified_gmt":"2011-12-02T20:23:55","slug":"securitycontext-fur-acegi-mit-request-scope","status":"publish","type":"post","link":"https:\/\/cogito-ergo-blog.de\/blog\/2007\/08\/07\/securitycontext-fur-acegi-mit-request-scope\/","title":{"rendered":"SecurityContext f\u00fcr Acegi mit Request-Scope"},"content":{"rendered":"<h3>Acegi Security-Framework f\u00fcr Spring<\/h3>\n<p>\nWenn man mit Spring statt mit EJB arbeitet, ist ein Aspekt, welcher normalerweise komplett vom ApplikationServer abgedeckt wird, die Sicherheit. Hierzu gibt es die Standard-L\u00f6sung, die auch in vielen Artikeln und B\u00fcchern erw\u00e4hnt und besprochen ist: <a href=\"http:\/\/www.acegisecurity.org\/\">Acegi<\/a>\n<\/p>\n<p>\nZusammen mit <a href=\"http:\/\/www.springframework.org\/\">Spring<\/a>, lassen sich per AOP Interceptoren beim Zugriff auf Businessmethoden von SpringBeans dazwischen &#8220;weben&#8221;, die die Authentisierung des Aufrufers \u00fcberwachen. Acegi benutzt hierzu einen SecurityContext, der auf unterschiedlichste Weise entstehen und bef\u00fcllt werden kann.\n<\/p>\n<p>In meinem konkreten Anwendungsfall wurde die Authentisierung einer WebApplikation mittels HTTP-Basic-Authentication realisiert und in der ersten zun\u00e4chst scheinbar korrekten Konfiguration zeigten sich seltsame Effekte:<\/p>\n<blockquote><p>\nNeben den Zugriffen, die richtig authentisiert waren und demnach ohne weiteres ausgef\u00fchrt wurden, konnte es passieren, dass manchmal auch ein nicht authentisierter Aufruf durchkam?\n<\/p><\/blockquote>\n<p>Wie sich heraus stellte, lebt der SecurityContext in einem ThreadLocal was im ApplikationenServer (hier Tomcat) mit dem jeweiligen WorkerThread assoziiert ist. Nun konnte es passieren, dass die SecurityContext eines vergangenen Requests &#8220;\u00fcberlebt&#8221; hat und bei einem erneuten Zugriff wiederbenutzt wurde. So waren Zugriffe die zuf\u00e4llig mit dem &#8220;richtigen&#8221; WorkerThread ausgef\u00fchrt wurden, falsch authentisiert.\n<\/p>\n<p>Was hier fehlt (und in Acegi ist das nicht vorhanden) ist ein LifeCycle des SecurityContexts der sich am Request orientiert. Was Acegi bietet ist die Kontrolle des LifeCycles \u00fcber eine Instance von &#8220;SecurityContextHolderStrategy&#8221; und eine solche &#8220;Strategy&#8221; f\u00fcr HTTP-Requests will ich hier einmal vorstellen.\n<\/p>\n<p><!--more--><\/p>\n<h3>Ein Listener f\u00fcr den Request<\/h3>\n<p>\nDer Schl\u00fcssel zum Request-Based-Lifecycle ist ein ContextListener, der das Erzeugen und Zerst\u00f6ren des Requests mitbekommt. Daran l\u00e4\u00dft sich der LifeCycle des SecurityContexts koppeln. <br \/>\nIm konkreten Fall ist eigentlich nicht viel mehr zu tun, als die Authentisierung des SecurityContexts am Ende eines jeden Requests zu l\u00f6schen. Daf\u00fcr sorgt dieser Listener:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n    package com.rinke.solutions.listener;\r\n\r\n    import javax.servlet.ServletRequestEvent;\r\n    import javax.servlet.ServletRequestListener;\r\n    import org.acegisecurity.context.SecurityContextHolder;\r\n\r\n    \/**\r\n    * listener class that clears the security context of acegi at the end of the request.\r\n    * @author sr\r\n    *\/\r\n    public class RequestContextListener implements ServletRequestListener {\r\n\r\n        public void requestDestroyed(ServletRequestEvent evt) {\r\n            SecurityContextHolder.clearContext();\r\n        }\r\n\r\n        public void requestInitialized(ServletRequestEvent evt) {\r\n        }\r\n    } \r\n<\/pre>\n<p>Dieser Listener wird in der web.xml gleich zu Beginn entsprechend eingetragen mehr braucht man nicht zu tun. So k\u00f6nnen die Effekte, die oben beschrieben wurden, nicht mehr auftreten.\n<\/p>\n<p>\nAlternativ kann man den SecurityContext auf mit Hilfe eines Filters l\u00f6schen, den man in die Request-Verarbeitung einklinkt. Ein solcher Filter macht nichts, ausser am Ende den SecurityContext im Finally-Block zu l\u00f6schen:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n    package com.rinke.solutions.acegi.filter;\r\n\r\n    import java.io.IOException;\r\n\r\n    import javax.servlet.Filter;\r\n    import javax.servlet.FilterChain;\r\n    import javax.servlet.FilterConfig;\r\n    import javax.servlet.ServletException;\r\n    import javax.servlet.ServletRequest;\r\n    import javax.servlet.ServletResponse;\r\n    import org.acegisecurity.context.SecurityContextHolder;\r\n\r\n    \/**\r\n    * simple filter, that clears the acegi security context at the end of the request.\r\n    * be sure to install it on every request, that is guarded by acegi, when using a\r\n    * request based lifecycle of the security context.\r\n    * @author sr\r\n    *\r\n    *\/\r\n    public class RequestFilter implements Filter {\r\n\r\n        public void destroy() {\r\n        }\r\n\r\n        public void doFilter(ServletRequest req, ServletResponse res,\r\n                FilterChain chain) throws IOException, ServletException {\r\n            try {\r\n                chain.doFilter(req, res);\r\n            } finally {\r\n                SecurityContextHolder.clearContext();\r\n            }\r\n        }\r\n\r\n        public void init(FilterConfig conf) throws ServletException {\r\n        }\r\n    }\r\n<\/pre>\n<p>Bei der Filterl\u00f6sung darf man allerdings nicht vergessen, dass der Filter auch ganz bestimmt auf alle Requests konfiguriert wird, die mit Acegi gesch\u00fctzt werden.\n<\/p>\n<p>\nEin komplettes Bespiel mit beiden Varianten kann man <a href=\"http:\/\/www.stefan-rinke.de\/download\/acegitest.zip\">hier<\/a> herunterladen. Es nutzt ein simples SpringServlet, welches wiederum eine SpringBean aufruft, deren eine Methode von Acegi gesch\u00fctzt wird, die genaue Konfiguration kann man im applicationContext.xml nachlesen. Ein TestRequest sollte auf &#8230;\/test oder &#8230;\/test?protected=true erfolgen, dann sieht man im letzteren Fall die Authenisierungsaufforderung.<br \/>\nDie echte Applikation sch\u00fctzt auf die gleiche Weise Zugriffe auf einen WebService, deren Delegates auch durch SpringBeans dargestellt werden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Acegi Security-Framework f\u00fcr Spring Wenn man mit Spring statt mit EJB arbeitet, ist ein Aspekt, welcher normalerweise komplett vom ApplikationServer abgedeckt wird, die Sicherheit. Hierzu gibt es die Standard-L\u00f6sung, die auch in vielen Artikeln und B\u00fcchern erw\u00e4hnt und besprochen ist: &hellip; <a href=\"https:\/\/cogito-ergo-blog.de\/blog\/2007\/08\/07\/securitycontext-fur-acegi-mit-request-scope\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"_links":{"self":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/29"}],"collection":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=29"}],"version-history":[{"count":3,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/29\/revisions"}],"predecessor-version":[{"id":10044,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/29\/revisions\/10044"}],"wp:attachment":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=29"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=29"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=29"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}