Communardo Software GmbH, Kleiststraße 10 a, D-01129 Dresden
0800 1 255 255

CoreMedia und Spring Security verheiratet - Teil 1: Authentifizierung

Erstellung eines CoreMedia-AuthenticationProviders für das Spring Security Framework

Einleitung und Funktionsweise

Neben dem Aufbau von geschlos­se­nen Benutzergruppen (GBGs) im CMS kann es auch andere Gründe geben, das CoreMedia UserRepository für die Authentifizierung von Nutzern zu ver­wen­den. Das Spring Security Framework (ehe­mals ACEGI Security) bie­tet Funktionalitäten für die Authentifizierung und Autorisierung von Nutzern. Im Folgenden Klassendiagramm sind die Interfaces und Klassen für die Authentifizierung dar­ge­stellt.

uml

Standardmäßig sind im Framework bereits ver­schie­dene Implementierungen vor­han­den (z.B. für Datenbanken, LDAP u.a.). Mit wenig Aufwand kann man eigene Implementierungen wie die gegen das CoreMedia UserRepository imple­men­tie­ren.

Der AuthenticationManager ist der zen­trale Einstieg für die Authentifizierung. Er kann meh­rere ver­schie­dene AuthenticationProvider ver­wal­ten. Über das Authentication-Objekt kann die Authentifizierung nur durch gewünschte Provider erfol­gen (AuthenticationProvider#supports(Class authentication)).
Der UserDetailsService lädt das User-Objekt aus dem jewei­li­gen Repository per Namen (#loadUserByUsername(String user­name)). Der Provider über­prüft das Passwort mit der Methode additionalAuthenticationChecks(...).

Implementierung

public class CMUserDao implements UserDetailsService{
...
public UserDetails loadUserByUsername(String username)
  throws UsernameNotFoundException, DataAccessException {
UserRepository userRepository = capConnection.getUserRepository();
org.acegisecurity.userdetails.User user = null;
try {
Repository repository = ContentRepositoryFactory.instance().getContentRepository();
User cmsUser = userRepository.getUserByName(username);
Collection < Group > groups = new ArrayList < Group >();
if (cmsUser != null) {
  groups = cmsUser.getGroups();
} else {
  throw new UsernameNotFoundException(username);
}
Collection < GrantedAuthority > authorities = new ArrayList < GrantedAuthority >();
if (groups != null) {
  for (Group group : groups) {
    authorities.add(new GrantedAuthorityImpl(group.getName()));
  }
}
user = new org.acegisecurity.userdetails.User(username, "", true, true, true, true,
  authorities.toArray(new GrantedAuthority[0]));
} catch (InvalidLoginException e) {
  throw new BadCredentialsException(e.getMessage(), e);
} catch (LicensesExceededException e) {
  new BadCredentialsException(e.getMessage(), e);
} catch (ConnectionNotOpenException e) {
  new BadCredentialsException(e.getMessage(), e);
}
return user;
}
...
}
public class CMAuthenticationProvider extends
    AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider {
...
protected void additionalAuthenticationChecks(UserDetails aUserDetails,
      UsernamePasswordAuthenticationToken aAuthenticationToken)
      throws AuthenticationException {

    String username = aUserDetails.getUsername();
    String password = aAuthenticationToken.getCredentials().toString();   

    boolean isValid = capConnection.isValidLogin(username, null, password);

    if (!isValid) {
      throw new BadCredentialsException(messages.getMessage(
          "AbstractUserDetailsAuthenticationProvider.badCredentials",
          "Bad credentials"), aUserDetails);
    }
  }
...
}

Benutzt man den AuthenticationProcessingFilter aus dem Framework wird nach erfolg­rei­cher Authentifizierung das Authentication-Objekt in den SecurityContext gela­den, einer ThreadLocal-Variable. Benutzt man einen eige­nen Controller, muss man dies von Hand machen.

auth = authenticationManager.authenticate(...);
SecurityContextHolder.getContext().setAuthentication(auth);

Spring-Konfiguration

<bean id="authenticationProcessingFilter"
  class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager"><ref bean="authenticationManager"/></property>
  ...
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
  <property name="providers">
    <list>
      <ref local="cmsDaoAuthenticationProvider" />
    </list>
  </property>
</bean>

<bean id="cmsDao" class="de.mse.authentication.CMUserDao"/>

<bean id="cmsDaoAuthenticationProvider"
  class="de.mse.authentication.CMAuthenticationProvider">
  <property name="userDetailsService">
    <ref bean="cmsDao"/>
  </property>
</bean>

Links

Related Posts

Pin It on Pinterest