Erstellung eines CoreMedia-AuthenticationProviders für das Spring Security Framework
Einleitung und Funktionsweise
Neben dem Aufbau von geschlossenen Benutzergruppen (GBGs) im CMS kann es auch andere Gründe geben, das CoreMedia UserRepository für die Authentifizierung von Nutzern zu verwenden. Das Spring Security Framework (ehemals ACEGI Security) bietet Funktionalitäten für die Authentifizierung und Autorisierung von Nutzern. Im Folgenden Klassendiagramm sind die Interfaces und Klassen für die Authentifizierung dargestellt.
Standardmäßig sind im Framework bereits verschiedene Implementierungen vorhanden (z.B. für Datenbanken, LDAP u.a.). Mit wenig Aufwand kann man eigene Implementierungen wie die gegen das CoreMedia UserRepository implementieren.
Der AuthenticationManager
ist der zentrale Einstieg für die Authentifizierung. Er kann mehrere verschiedene AuthenticationProvider
verwalten. Über das Authentication
-Objekt kann die Authentifizierung nur durch gewünschte Provider erfolgen (AuthenticationProvider#supports(Class authentication)
).
Der UserDetailsService
lädt das User-Objekt aus dem jeweiligen Repository per Namen (#loadUserByUsername(String username)). Der Provider überprü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 erfolgreicher Authentifizierung das Authentication-Objekt in den SecurityContext
geladen, einer ThreadLocal-Variable. Benutzt man einen eigenen 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
[…] Teil1: Authentifizierung […]