{"id":104,"date":"2012-06-27T18:18:08","date_gmt":"2012-06-27T16:18:08","guid":{"rendered":"http:\/\/marko-seifert.de\/blog\/?p=104"},"modified":"2020-01-15T12:23:37","modified_gmt":"2020-01-15T10:23:37","slug":"coremedia-und-spring-security-verheiratet-teil-2-autorisierung","status":"publish","type":"post","link":"http:\/\/marko-seifert.de\/blog\/?p=104","title":{"rendered":"CoreMedia und Spring Security verheiratet \u2013 Teil 2: Autorisierung"},"content":{"rendered":"<h2>Rechte und Rollen<\/h2>\n<p>Mit dem CoreMedia JavaEditor k\u00f6nnen Berechtigungsgruppen oder Rollen erstellt und Nutzern zugeordnet werden. \u00dcber die Gruppen k\u00f6nnen Berechtigungen sehr feingranular auf Dokumentebene eingestellt werden.<\/p>\n<p><a href=\"http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/javaeditor.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-106\" title=\"javaeditor\" src=\"http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/javaeditor-300x195.png\" alt=\"\" width=\"300\" height=\"195\" srcset=\"http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/javaeditor-300x195.png 300w, http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/javaeditor-460x300.png 460w, http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/javaeditor.png 791w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p>Bei der Authentifizierung wird das Nutzerobjekt mit seinen Berechtigungen (<a href=\"http:\/\/static.springsource.org\/spring-security\/site\/apidocs\/org\/springframework\/security\/GrantedAuthority.html\" target=\"_blank\">GrantedAuthority<\/a>) geladen und im <a href=\"http:\/\/static.springsource.org\/spring-security\/site\/apidocs\/org\/springframework\/security\/context\/SecurityContext.html\" target=\"_blank\">SecurityContext <\/a>abgelegt. F\u00fcr die Autorisierung kann in allen Schichten der Architektur darauf zugegriffen werden.<\/p>\n<h2>Autorisierung im Template<\/h2>\n<p>Wenn es sich um einfache rollenbasierte Autorisierung handelt, kann die <a href=\"http:\/\/static.springframework.org\/spring-security\/site\/reference\/html\/authorization-common.html#authorization-taglibs\" target=\"_blank\">authorize-Taglib<\/a> aus dem Framework benutzt werden.<\/p>\n<pre>&lt;authz:authorize ifAllGranted=\"ROLE_SUPERVISOR\"&gt;\r\n&lt;td&gt;\r\n&lt;A HREF=\"del.htm?id=&lt;c:out value=\"${contact.id}\"\/&gt;\"&gt;Del&lt;\/A&gt;\r\n&lt;\/td&gt;\r\n&lt;\/authz:authorize&gt;<\/pre>\n<p>Die Autorisierung mit Berechtigungsgruppen (Bean-basierte Autorisierung) ist komplexer. Je nach Berechtigung des Nutzers sollen unterschiedliche Inhalte aus dem CMS dargestellt werden. Es empfiehlt sich, die Funktionalit\u00e4t f\u00fcr die Pr\u00fcfung der Berechtigung in eine eigene Komponente (<code>AuthorizationUtils<\/code>) auszulagern, da diese auch z.B. bei den Controllern verwendet werden kann.<\/p>\n<p><strong>AuthorizationUtils<\/strong><\/p>\n<pre>public class AuthorizationUtils{\r\n  ...\r\n  public boolean isAccessAllowed(Content content){\r\n\r\n    GrantedAuthority[] grants = null;\r\n    if (SecurityContextHolder.getContext().getAuthentication() != null) {\r\n      grants = SecurityContextHolder\r\n        .getContext().getAuthentication().getAuthorities();\r\n    }\r\n    int length = (grants != null) ? grants.length : 0;\r\n    String[] groupnames = new String[length];\r\n    for (int i = 0; i &lt; length; i++) {\r\n      groupnames[i] = grants[i].getAuthority();\r\n    }\r\n    LinkedList groups = getGroups(groupnames);\r\n\r\n    if (groups != null &amp;&amp; getAccessControl().mayRead(content, groups)) {\r\n      isAccessAllowed = true;\r\n    } else {\r\n      isAccessAllowed = false;\r\n    }\r\n    return isAccessAllowed;\r\n  }\r\n\r\n  private LinkedList getGroups(String[] groupNames) {\r\n    LinkedList groups = new LinkedList();\r\n    for (int i = 0; groupNames != null &amp;&amp; i &lt; groupNames.length; i++) {\r\n      Group group = userRepository.getGroupByName(groupName, null);\r\n      if (group != null) {\r\n        groups.add(group);\r\n      }\r\n\r\n    }\r\n    return groups;\r\n  }\r\n  private AccessControl getAccessControl() throws MipException {\r\n    AccessControl accessControl = getRepository().getAccessControl();\r\n    return accessControl ;\r\n  }\r\n  ...<\/pre>\n<pre>}<\/pre>\n<p><strong>Authorize-Tag Library<\/strong><\/p>\n<pre>public class Authorize extends TagSupport {\r\n\r\n  private ContentBean contentBean;\r\n\r\n  public int doStartTag() {\r\n    if (null == bean) {\r\n      return SKIP_BODY;\r\n    }\r\n\r\n    ApplicationContext context = getContext(pageContext);\r\n    AuthorizationUtils authorizationUtils = (AuthorizationUtils)\r\n      context.getBean(\"authorizationUtils\");\r\n    try {\r\n      if (authorizationUtils.isAccessAllowed(bean.getContent(),\r\n          null, (HttpServletRequest) pageContext\r\n          .getRequest())) {\r\n        return EVAL_BODY_INCLUDE;\r\n      }\r\n    } catch (Exception e) {\r\n      e.printStackTrace();\r\n    }\r\n\r\n    return SKIP_BODY;\r\n  }\r\n\r\n  protected ApplicationContext getContext(PageContext pageContext) {\r\n    ServletContext servletContext = pageContext.getServletContext();\r\n\r\n    return WebApplicationContextUtils\r\n        .getRequiredWebApplicationContext(servletContext);\r\n  }\r\n  public ContentBean getContentBean() {\r\n    return contentBean;\r\n  }\r\n  public void setContentBean(ContentBean contentBean) {\r\n    contentBean = contentBean;\r\n  }\r\n\r\n}<\/pre>\n<p><strong>Einbindung im Template<\/strong><\/p>\n<pre>&lt;mse:authorize contentBean=\"${self}\"&gt;\r\n  &lt;c:out value=\"${self.name}\" \/&gt;\r\n&lt;\/mse:authorize&gt;<\/pre>\n<h3>Autorisierung im Controller<\/h3>\n<p>Auch im Controller kann man den bereits vorgestellten Bean-basierten Autorisierungsmechanismus verwenden, um z.B. komplette Seitenaufrufe zu verhindern.<\/p>\n<p><strong>SecureContentViewController<\/strong><\/p>\n<pre>public class SecureContentViewController extends ContentViewController {\r\n\r\n\u00a0 private AuthorizationUtils authorizationUtils;\r\n\r\n\u00a0 protected Object resolveBean(String controllerPathInfo,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 Map parameters, HttpServletRequest request) {\r\n\u00a0\u00a0 ...\r\n\u00a0 }\r\n\r\n\u00a0 protected String resolveView(String controllerPathInfo,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 Map parameters, HttpServletRequest request) {\r\n\u00a0\u00a0\u00a0 ...\r\n\u00a0 }\r\n\r\n\u00a0 protected ModelAndView handleRequestInternal(HttpServletRequest request,\r\n\u00a0\u00a0\u00a0 HttpServletResponse response) throws Exception {\r\n\r\n\u00a0\u00a0\u00a0 String pathInfo = controllerPathInfo(HttpServletRequest request);\r\n\u00a0\u00a0\u00a0 Object bean = resolveBean(pathInfo, request.getParameterMap(), request);\r\n\r\n\u00a0\u00a0\u00a0 ContentBean contentBean = (ContentBean) bean;\r\n\r\n\u00a0\u00a0\u00a0 if (!authorizationUtils.isAccessAllowed(contentBean.getContent())) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Fehlerbehandlung\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return new ModelAndView(new RedirectView(LOGIN_URL));\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 return super.handleRequestInternal(request, response);\r\n\u00a0 }\r\n\u00a0 ...\r\n}<\/pre>\n<h3>Autorisierung auf Business-Methoden<\/h3>\n<p>Das Thema methodenbasierte Security kann man elegant mit den Mitteln der <a href=\"http:\/\/de.wikipedia.org\/wiki\/Aspektorientierte_Programmierung\" target=\"_blank\">aspektorientierten Programmierung<\/a> (AOP) l\u00f6sen. Neben Frameworks wie <a href=\"http:\/\/www.eclipse.org\/aspectj\/\" target=\"_blank\">aspectJ<\/a> bietet auch Spring mit Dynamic Proxys eine <a href=\"http:\/\/static.springframework.org\/spring\/docs\/2.0.x\/reference\/aop-api.html\" target=\"_blank\">AOP-Implementierung<\/a>.<\/p>\n<p><strong>CheckPermissionInterceptor<\/strong><\/p>\n<pre>public class CheckPermissionInterceptor implements MethodInterceptor {\r\n\r\n\u00a0 public Object invoke(MethodInvocation aMethodInvocation) throws Throwable {\r\n\u00a0\u00a0\u00a0 initSecureMethodsMap();\r\n\r\n\u00a0\u00a0\u00a0 String currentMethode = aMethodInvocation.getMethod().getName();\r\n\r\n\u00a0\u00a0\u00a0 \/\/ ist SecureMethode\r\n\u00a0\u00a0\u00a0 if (secureMethodsMap.containsKey(currentMethode)) {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 Authentication authentication = SecurityContextHolder.getContext()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .getAuthentication();\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 GrantedAuthority[] auth = authentication.getAuthorities();\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 int length = (auth != null) ? auth.length : 0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 String[] roleNames = new String[length];\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 for (int i = 0; auth != null &amp;&amp; i &lt; auth.length; i++) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 roleNames[i] = auth[i].getAuthority();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 String roles = (String) secureMethodsMap.get(currentMethode);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if(!checkPermission(roles, roleNames){\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Keine Rechte\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 throw new AccessDeniedException(\"User hat nicht gen\u00fcgend Rechte\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 return aMethodInvocation.proceed();\r\n\u00a0 }\r\n\u00a0 private boolean checkPermission(String allowedRoles, String[] availableRoles){\r\n\u00a0\u00a0\u00a0 for (int i = 0; i &lt; availableRoles.length; i++) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if(allowedRoles.indexOf(availableRoles[i])!=-1){\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 return false;\r\n\u00a0 }\r\n}<\/pre>\n<p>In der Spring-Konfiguration wird ein Dynamic Proxy mit dem Namen des Services konfiguriert. Der Proxy kennt den Service unter der Property target. Die Service-Aufrufe werden so durch den Proxy abgefangen. Nun kommt der Interceptor ins Spiel. Er pr\u00fcft f\u00fcr konfigurierte Methoden die Berechtigung. Ist alles o.k., wird die Anfrage an den eigentlichen Service delegiert.<\/p>\n<p><strong>Spring-Konfiguration<\/strong><\/p>\n<pre>&lt;beans&gt;\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0 &lt;bean id=\"aServiceTarget\"&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 ...\r\n\u00a0\u00a0\u00a0 &lt;\/bean&gt;\r\n\r\n\u00a0\u00a0\u00a0 &lt;bean id=\"aService\"\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;property name=\"proxyInterfaces\"&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;value&gt;de.mse.business.IService&lt;\/value&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;\/property&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;property name=\"target\"&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;ref bean=\"aServiceTarget\"\/&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;\/property&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;property name=\"interceptorNames\"&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;list&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;value&gt;checkPermissionInterceptor&lt;\/value&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;\/list&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;\/property&gt;\r\n\u00a0\u00a0\u00a0 &lt;\/bean&gt;\r\n\u00a0\u00a0\u00a0 &lt;bean id=\"checkPermissionInterceptor\"\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;property name=\"secureMethods\"&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;value&gt;\r\n               methode1=ADMIN\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0 methode2=ADMIN, REDAKTEUR\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0        ...\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;\/value&gt;\r\n\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 &lt;\/property&gt;\r\n\u00a0\u00a0\u00a0 &lt;\/bean&gt;\r\n&lt;\/beans&gt;<\/pre>\n<h2>Links<\/h2>\n<ul>\n<li><a href=\"http:\/\/www.acegisecurity.org\/\" target=\"_blank\">ACEGI Security<\/a><\/li>\n<li><a href=\"http:\/\/static.springsource.org\/spring-security\/site\/index.html\" target=\"_blank\">Spring Security Framework<\/a><\/li>\n<li><a href=\"http:\/\/java.sun.com\/products\/jsp\/tutorial\/TagLibrariesTOC.html\" target=\"_blank\">Tag Libraries Tutorial<\/a><\/li>\n<li><a href=\"http:\/\/de.wikipedia.org\/wiki\/Aspektorientierte_Programmierung\" target=\"_blank\">Aspektorientierten Programmierung<\/a> (AOP)<\/li>\n<li><a href=\"http:\/\/www.eclipse.org\/aspectj\/\" target=\"_blank\">aspectJ<\/a><\/li>\n<li>Spring <a href=\"http:\/\/static.springframework.org\/spring\/docs\/2.0.x\/reference\/aop-api.html\" target=\"_blank\">AOP-Implementierung<\/a><\/li>\n<li><a title=\"CoreMedia und Spring Security verheiratet \u2013 Teil 1: Authentifizierung\" href=\"http:\/\/marko-seifert.de\/blog\/?p=96\">Teil1: Authentifizierung<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Rechte und Rollen Mit dem CoreMedia JavaEditor k\u00f6nnen Berechtigungsgruppen oder Rollen erstellt und Nutzern zugeordnet werden. \u00dcber die Gruppen k\u00f6nnen Berechtigungen sehr feingranular auf Dokumentebene eingestellt werden.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16,38,4],"tags":[36,40,162,17,164,31,39],"class_list":["post-104","post","type-post","status-publish","format-standard","hentry","category-cms","category-coremedia","category-java","tag-acegi-security","tag-autorisierung","tag-cms","tag-content-management","tag-coremedia","tag-security","tag-spring-security"],"_links":{"self":[{"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/104","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=104"}],"version-history":[{"count":7,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/104\/revisions"}],"predecessor-version":[{"id":331,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/104\/revisions\/331"}],"wp:attachment":[{"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=104"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=104"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=104"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}