{"id":96,"date":"2012-06-27T16:11:54","date_gmt":"2012-06-27T14:11:54","guid":{"rendered":"http:\/\/marko-seifert.de\/blog\/?p=96"},"modified":"2020-01-15T12:23:37","modified_gmt":"2020-01-15T10:23:37","slug":"coremedia-und-spring-security-verheiratet-teil-1-authentifizierung","status":"publish","type":"post","link":"http:\/\/marko-seifert.de\/blog\/?p=96","title":{"rendered":"CoreMedia und Spring Security verheiratet \u2013 Teil 1: Authentifizierung"},"content":{"rendered":"<p><em><strong>Erstellung eines CoreMedia-AuthenticationProviders f\u00fcr das Spring Security Framework<\/strong><\/em><\/p>\n<h2>Einleitung und Funktionsweise<\/h2>\n<p>Neben dem Aufbau von geschlossenen Benutzergruppen (GBGs) im CMS kann es auch andere Gr\u00fcnde geben, das CoreMedia UserRepository f\u00fcr die Authentifizierung von Nutzern zu verwenden. Das <a href=\"http:\/\/static.springsource.org\/spring-security\/site\/index.html\" target=\"_blank\">Spring Security Framework<\/a> (ehemals <a href=\"http:\/\/www.acegisecurity.org\/\" target=\"_blank\">ACEGI Security<\/a>) bietet Funktionalit\u00e4ten f\u00fcr die Authentifizierung und Autorisierung von Nutzern. Im Folgenden Klassendiagramm sind die Interfaces und Klassen f\u00fcr die Authentifizierung dargestellt.<\/p>\n<p><a href=\"http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/uml.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-98\" title=\"uml\" src=\"http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/uml.gif\" alt=\"\" width=\"644\" height=\"882\" srcset=\"http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/uml.gif 644w, http:\/\/marko-seifert.de\/blog\/wp-content\/uploads\/2012\/06\/uml-219x300.gif 219w\" sizes=\"auto, (max-width: 644px) 100vw, 644px\" \/><\/a><\/p>\n<p><!--more--><\/p>\n<p>Standardm\u00e4\u00dfig sind im Framework bereits verschiedene Implementierungen vorhanden (z.B. f\u00fcr Datenbanken, LDAP u.a.). Mit wenig Aufwand kann man eigene Implementierungen wie die gegen das CoreMedia UserRepository implementieren.<\/p>\n<p>Der<code><a href=\"http:\/\/static.springsource.org\/spring-security\/site\/apidocs\/org\/springframework\/security\/AuthenticationManager.html\" target=\"_blank\">AuthenticationManager<\/a> <\/code>ist der zentrale Einstieg f\u00fcr die Authentifizierung. Er kann mehrere verschiedene <a href=\"http:\/\/static.springsource.org\/spring-security\/site\/apidocs\/org\/springframework\/security\/providers\/AuthenticationProvider.html\" target=\"_blank\"><code>AuthenticationProvider<\/code> <\/a>verwalten. \u00dcber das <a href=\"http:\/\/static.springsource.org\/spring-security\/site\/apidocs\/index.html?org\/springframework\/security\/userdetails\/UserDetailsService.html\" target=\"_blank\"><code>Authentication<\/code><\/a>-Objekt kann die Authentifizierung nur durch gew\u00fcnschte Provider erfolgen (<code>AuthenticationProvider#supports(Class authentication)<\/code>).<br \/>\nDer <a href=\"http:\/\/static.springsource.org\/spring-security\/site\/apidocs\/org\/springframework\/security\/userdetails\/UserDetailsService.html\" target=\"_blank\"><code>UserDetailsService<\/code><\/a> l\u00e4dt das User-Objekt aus dem jeweiligen Repository per Namen (#loadUserByUsername(String username)). Der Provider \u00fcberpr\u00fcft das Passwort mit der Methode <code>additionalAuthenticationChecks(...)<\/code>.<\/p>\n<h2>Implementierung<\/h2>\n<pre>public class CMUserDao implements UserDetailsService{\r\n...\r\npublic UserDetails loadUserByUsername(String username)\r\n  throws UsernameNotFoundException, DataAccessException {<\/pre>\n<pre>UserRepository userRepository = capConnection.getUserRepository();<\/pre>\n<pre>org.acegisecurity.userdetails.User user = null;\r\ntry {\r\nRepository repository = ContentRepositoryFactory.instance().getContentRepository();\r\nUser cmsUser = userRepository.getUserByName(username);<\/pre>\n<pre>Collection &lt; Group &gt; groups = new ArrayList &lt; Group &gt;();\r\nif (cmsUser != null) {\r\n  groups = cmsUser.getGroups();\r\n} else {\r\n  throw new UsernameNotFoundException(username);\r\n}<\/pre>\n<pre>Collection &lt; GrantedAuthority &gt; authorities = new ArrayList &lt; GrantedAuthority &gt;();<\/pre>\n<pre>if (groups != null) {\r\n  for (Group group : groups) {\r\n    authorities.add(new GrantedAuthorityImpl(group.getName()));\r\n  }\r\n}\r\nuser = new org.acegisecurity.userdetails.User(username, \"\", true, true, true, true,\r\n  authorities.toArray(new GrantedAuthority[0]));<\/pre>\n<pre>} catch (InvalidLoginException e) {\r\n  throw new BadCredentialsException(e.getMessage(), e);\r\n} catch (LicensesExceededException e) {\r\n  new BadCredentialsException(e.getMessage(), e);\r\n} catch (ConnectionNotOpenException e) {\r\n  new BadCredentialsException(e.getMessage(), e);\r\n}<\/pre>\n<pre>return user;\r\n}\r\n...\r\n}<\/pre>\n<pre>public class CMAuthenticationProvider extends\r\n    AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider {\r\n...\r\nprotected void additionalAuthenticationChecks(UserDetails aUserDetails,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 UsernamePasswordAuthenticationToken aAuthenticationToken)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 throws AuthenticationException {\r\n\r\n\u00a0\u00a0\u00a0 String username = aUserDetails.getUsername();\r\n\u00a0\u00a0\u00a0 String password = aAuthenticationToken.getCredentials().toString();\u00a0\u00a0\u00a0\r\n\r\n\u00a0\u00a0\u00a0 boolean isValid = capConnection.isValidLogin(username, null, password);\r\n\r\n\u00a0\u00a0\u00a0 if (!isValid) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 throw new BadCredentialsException(messages.getMessage(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"AbstractUserDetailsAuthenticationProvider.badCredentials\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"Bad credentials\"), aUserDetails);\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0 }\r\n...\r\n}<\/pre>\n<p>Benutzt man den <code>AuthenticationProcessingFilter <\/code>aus dem Framework wird nach erfolgreicher Authentifizierung das Authentication-Objekt in den <code>SecurityContext <\/code>geladen, einer ThreadLocal-Variable. Benutzt man einen eigenen Controller, muss man dies von Hand machen.<\/p>\n<pre>auth = authenticationManager.authenticate(...);<\/pre>\n<pre>SecurityContextHolder.getContext().setAuthentication(auth);<\/pre>\n<h2>Spring-Konfiguration<\/h2>\n<pre>&lt;bean id=\"authenticationProcessingFilter\"\r\n &gt;\r\n  &lt;property name=\"authenticationManager\"&gt;&lt;ref bean=\"authenticationManager\"\/&gt;&lt;\/property&gt;\r\n\u00a0 ...\r\n&lt;\/bean&gt;\r\n&lt;bean id=\"authenticationManager\"&gt;\r\n  &lt;property name=\"providers\"&gt;\r\n    &lt;list&gt;\r\n      &lt;ref local=\"cmsDaoAuthenticationProvider\" \/&gt;\r\n    &lt;\/list&gt;\r\n  &lt;\/property&gt;\r\n&lt;\/bean&gt;\r\n\r\n&lt;bean id=\"cmsDao\"\/&gt;\r\n\r\n&lt;bean id=\"cmsDaoAuthenticationProvider\"\r\n &gt;\r\n  &lt;property name=\"userDetailsService\"&gt;\r\n    &lt;ref bean=\"cmsDao\"\/&gt;\r\n  &lt;\/property&gt;\r\n&lt;\/bean&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 title=\"CoreMedia und Spring Security verheiratet \u2013 Teil 2: Autorisierung\" href=\"http:\/\/marko-seifert.de\/blog\/?p=104\">Teil2: Autorisierung<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Erstellung eines CoreMedia-AuthenticationProviders f\u00fcr das Spring Security Framework Einleitung und Funktionsweise Neben dem Aufbau von geschlossenen Benutzergruppen (GBGs) im CMS kann es auch andere Gr\u00fcnde geben, das CoreMedia UserRepository f\u00fcr die Authentifizierung von Nutzern zu verwenden. Das Spring Security Framework (ehemals ACEGI Security) bietet Funktionalit\u00e4ten f\u00fcr die Authentifizierung und Autorisierung von Nutzern. Im Folgenden Klassendiagramm sind die Interfaces und Klassen f\u00fcr die Authentifizierung dargestellt.<\/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,11,4],"tags":[36,37,162,17,164,31,25,39],"class_list":["post-96","post","type-post","status-publish","format-standard","hentry","category-cms","category-coremedia","category-development","category-java","tag-acegi-security","tag-authentifizierung","tag-cms","tag-content-management","tag-coremedia","tag-security","tag-spring","tag-spring-security"],"_links":{"self":[{"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/96","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=96"}],"version-history":[{"count":10,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/96\/revisions"}],"predecessor-version":[{"id":332,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/96\/revisions\/332"}],"wp:attachment":[{"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=96"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=96"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/marko-seifert.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=96"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}