Grails: Acegi erweitern

Sollte es nötig sein, dass Acegi-Plugin z.B. für eine eigene SSO-Authentifzierung zu erweitern, ist das eigentlich recht einfach zu realisieren, um z.B. Nutzerdaten aus dem Request-Header zu lesen.

Eine Möglichkeit der Implementierung ist diese hier:

Der beste Platz für die eigenen Klassen sollte ein eigenes Package innerhalb der src/groovy bzw. src/java Ordner inenrhalb des Plugins sein.

Ein AuthenticationProcessingFilter, in welchem die folgenden Methoden für die eigenen Bedürfnisse implementiert werden müssen:

public Authentication attemptAuthentication(HttpServletRequest request)
protected String obtainUsername(HttpServletRequest request)
protected String obtainPassword(HttpServletRequest request)

Als nächstes benötigen wir ein AuthenticationToken, welches die Daten zur Authentifizierung für unsere Grails-Anwendung enthalten soll. Dieses Token muss die folgenden Interfaces implementieren:

Serializable
Principal
Authentication
Jetzt müssen wir noch einen eigenen AuthenticationProvider

implementieren, welcher die eigentliche Authentifizierung durchführt, in dem innerhalb des Tokens das FLAG isAuthenticated auf TRUE gesetzt wird. | Die AuthenticationProvider-Klasse enthält die folgenden Methoden:

public Authentication authenticate(Authentication authentication)
public boolean supports(Class arg0)

Die Method supports(Class arg0) sollte TRUE liefern, sofern es sich um eine Instanz des eigenen Tokens handelt.

Nun haben wir die Grundvoraussetzung für eine eigene Authentifizierungsmethode. Um die eigenen Funktionen nutzen zu können, müssen AuthenticationProvider und AuthenticationProcessingFilter in der Klasse AcegiGrailsPlugin konfiguriert werden.

Das AuthenticationToken wird dann im AuthenticationProcessingFilter zusammengebaut und an den AuthenticationManager weitergeleitet.

Am besten lässt sich das vielleicht an einem Beispiel erklären ....

AuthenticationToken

public class FooAuthenticationToken extends AbstractAuthenticationToken {
 private Object principal;

 @Deprecated
 public FooAuthenticationToken(Object principal) {
  this.principal = principal;
 }

 @Override
 public FooAuthenticationToken(Object principal, GrantedAuthority[] authorities) {
  super(authorities);
  this.principal = principal;
 }

 @Override
 public Object getCredentials() {
  return null;
 }

 @Override
 public Object getPrincipal() {
   return this.principal;
 }
}

AuthenticationProcessingFilter

public class FooAuthenticationProcessingFilter extends AuthenticationProcessingFilter {

 @Override
 public Authentication attemptAuthentication(HttpServletRequest request)
  throws AuthenticationException{

  FooAuthenticationToken token = new FooAuthenticationToken(obtainUsername(request))
  return this.getAuthenticationManager().authenticate(token)
 }
}

AuthenticationProvider

public class FooAuthenticationProvider implements AuthenticationProvider,
 InitializingBean, MessageSourceAware {

 @Override
 public Authentication authenticate(Authentication authentication)
  throws AuthenticationException {

  UserDetails user = retrieveUser(authentication.getName(), (FooAuthenticationToken) authentication);

  Object principalToReturn = user;
  if (forcePrincipalAsString) {
   principalToReturn = user.getUsername();
  }

  return createSuccessAuthentication(principalToReturn, authentication, user);
 }

 @Override
 public boolean supports(Class arg0) {
  return (FooAuthenticationToken.class.isAssignableFrom(arg0));
 }
}