Einen deklarativen Authentifizierungsansatz für Wicket Anwendungen bietet die Wicket Abstract Security Plattform (WASP). Bei diesem Ansatz wird in der Implementierung der IAuthorizationStrategy geprüft, ob an den Controls oder Container ISecurityCheck Objekte definiert wurden. Die ISecurityCheck Objekte delegieren die konkreten Abfragen zur Autorisierung der Actions an Erweiterungen der abstrakten Klasse WASPSecurityStrategy. Innerhalb der Strategy Implementierung wird die konkrete Autorisierungsprüfung umgesetzt.
Eine WASP-Implementierung ist Swarm. Swarm arbeitet auf Basis von Permissions. Geschützte Controls oder Container werden über Permissions freigegeben. Die Permissions werden über einen Principal konfiguriert, welcher keine konkrete Person sondern eine Rolle des angemeldeten Benutzers definiert. Alle Permissions werden in einer Hive-Datei verwaltet und wirken additiv, abhängig von den Rollen(Principals) des angemeldeten Benutz
Die größten Schwächen der aktuellen Implementierung liegen beim Sichern einzelner Controls. Zum einen müssen Controls in der Hive-Datei über den Wicket-PATH immer relativ zur Seite angegeben werden:
permission ${ComponentPermission} "de.path.to.secure.myControl",
"render, enable";
(${ComponentPermission} =org.apache.wicket.security.hive.authorization.permissions.ComponentPermission)
Zum anderen stehen als Secure-Controls nur wenige Elemente zur Verfügung, welche über Vererbung referenziert werden müssen. Durch die Vererbung entstehen Probleme beim Entwurf der Anwendung.
„Replace inheritance with composition“. Ein Grundsatz, welcher fast immer seine Berechtigung hat. Vererbung koppelt stark. Oft werden vom eigenen Architekturteam oder von einem Hersteller/Open-Source Framework/Beratungshaus erweiterte Controls zur Verfügung gestellt. Internationalisierung, AJAX-Verhalten oder andere projekt- bzw. firmenspezifischen Implementierungen werden in zentralen Komponenten gekapselt. Diese Kapselung geschieht im Rahmen von Controls oft über Vererbung. Um die SWARM Secure-Komponenten nun nutzen zu können, müsste das Verhalten von zwei Klassen geerbt werden – was bekanntlich aus guten Gründen in Java nicht geht.
Wicket bietet mit Behaviors ein Konzept, um Querschnittsaufgaben umzusetzen. Zwar ist das IBehavior-Interface stark auf das verändern von HTML-Code ausgelegt, es lässt sich aber auch für die Implementierung des Aspektes Security nutzen.
public class SecurityBehavior extends AbstractBehavior {
private final String hiveKey;
public SecurityBehavior(String hiveKey) {
this.hiveKey = hiveKey;
}
@Override
public void bind(Component component) {
SecureComponentHelper.setSecurityCheck(
component, new ComponentSecurityCheck(component));
component.setMetaData(new ComponentHiveKey(String.class)
, hiveKey);
}
}
Beim Binding der Component werden deren Metadaten um einen Hive-Key ergänzt. Dieser repräsentiert eindeutig die Komponente. Alternativ kann hier auch die Wicket-ID genutzt werden. Abhängig davon, wie oft diese schon in anderen Querschnittsaufgaben genutzt wird (Internationalisierung, Modelbinding etc.), kann es eine gute Idee sein, diese als Key für die Securitysettings zu verwenden.
Der ComponentHiveKey ist ein einfacher HashKey:
public class ComponentHiveKey extends MetaDataKey {
public ComponentHiveKey(Class type) {
super(type);
}
}
Was fehlt, ist die Auswertung des Hive-Keys. Standardmäßig wird der Wicket-Path verwendet. Bei komplexeren Anwendungen ist der Wicket-Path schwer lesbar. Zentrale Komponenten wie ListViews, Layoutmanager oder Select führen zu einem technischen String, welcher unter Umständen auch sehr lang ist. Des Weiteren sind Wicket-Path’s nicht sehr beständig. Bei jedem Umbau einer Page besteht die Gefahr, dass sich der Path eines Controlls ändert. Kurz gesagt: Der Wicket-Path ist nicht geeignet, um ihn als Key in einer Security-Datei zu verwenden.
Ein weiteres Problem ist die Relation des Wicket-Path’s zur Page. Der Key in Swarm ist der Klassenname der Seite, ergänzt um den Wicket-Path des Controls bis zur Page. Das führt neben dem langen unleserlichen Wicket-Path dazu, das Controls innerhalb von Widgets (Panels mit abgeschlossener Funktionaltät) innerhalb einer Seite nicht unterschiedlich berechtigt werden können. Was sich zunächst wie ein an den Haaren herbeigezogenes Argument anhört, wird bei größeren Wicketapplikationen, welche widgetorientiert entwickelt werden, schnell zur Realität. Verantwortlich für dieses Verhalten ist die Klasse ComponentPermission. Beim erstellen der Klasse wird der Key wie angesprochen erzeugt. Permissions sind das Bindeglied zwischen dem Wicket-Java Code und der Hive_Datei. Sie werden in der Hive-Datei verwendet, um die Berechtigungen der Wicket-Komponenten deklarativ zu steuern.
In der Operation isComponentAuthorized der Klasse warmStrategy wird die Permission von Controls geprüft. Dazu wird die Klasse ComponentPermission verwendet.
public boolean isClassAuthorized(Class clazz, WaspAction action)
{
return hasPermission(new ComponentPermission(
SecureComponentHelper.alias(clazz),
(SwarmAction)action));
}
Im angesprochenen Konstruktor der Klasse wird der Key aufgebaut. Neben dem Konstruktor mit Component existiert auch die Möglichkeit, den Key von außen mitzugeben. Folgende Erweiterung der SwarmStrategy ermöglicht deklarative Security auf Basis von Wicket-Behaviors:
public boolean isComponentAuthorized(Component component
, WaspAction action) {
if(containsBehavior(component, SecurityBehavior.class))
return hasPermission(newComponentPermission(buildHiveKey(
component), (SwarmAction)action));
else
return hasPermission(newComponentPermission(component
, (SwarmAction)action));
}
private String buildHiveKey(Component component) {
if(component == null)
throw new SecurityException("Specified component is null");
MarkupContainer markupContainer = findLowestSecureContainer(
component);
String alias = SecureComponentHelper.alias(markupContainer
.getClass());
String relative = (String) component.getMetaData(
new ComponentHiveKey(String.class));
if(relative == null|| "".equals(relative))
return alias;
return alias + ":"+ relative;
}
private MarkupContainer findLowestSecureContainer(Component component) {
finalMarkupContainer[] lowestSecureParent = newMarkupContainer[1];
component.visitParents(MarkupContainer.class, newIVisitor() {
public Object component(Component component) {
if(component instanceof ISecureComponent) {
lowestSecureParent[0] = (MarkupContainer) component;
return IVisitor.STOP_TRAVERSAL;
}
return null;
}
});
if(null== lowestSecureParent[0]) {
try{
lowestSecureParent[0] = component.getPage();
} catch(IllegalStateException e) {
throw new SecurityException(
"Unable to create alias for component: "+ component, e);
}
}
MarkupContainer markupContainer = lowestSecureParent[0];
return markupContainer;
}
private boolean containsBehavior(org.apache.wicket.Component component
,Class clazz) {
List<IBehavior> behaviors = component.getBehaviors();
for(IBehavior object : behaviors) {
if(object.getClass().isAssignableFrom(clazz)){
return true;
}
}
return false;
}
Diese Erweiterung der SWARM ermöglicht es, beliebige Komponenten über Einträge in einer Hive-Datei mit Security-Attributen zu versehen, um Autorisierungsprüfungen für diese Komponenten zu erreichen, ohne von speziellen Klassen ableiten zu müssen.
Über
Textfield tfToSecure = new Textfield(“tf”);
tfToSecure.add(new SecurityBehavior(„meinKey“);
kann beispielsweise ein normales Textfeld mit einem Security-Attribut versehen werden. Da Textfield nicht von einer SWARM Secure-Component abgeleitet ist, kann es ohne Erweiterungen nicht durch SWARM “gesichert” werden. Die in diesem Blog beschriebene Erweiterung durch SecurityBehaviours schafft diese Möglichkeit. Es kann in der Hive-Datei die folgende Permission definiert werden:
permission ${ComponentPermission} "de.path.to.secure.controll:meinKey", "render";
Erfahren Sie mehr über sichere Webanwendungen mit Apache Wicket in unserer mehrteiligen Reihe von Blogeinträgen:
Wicket Security
Wicket Security - Schutz vor SQL Injection durch Validatoren
Wicket Security - Keine CSRF Angriffe dank Security URL-Parameter
Wicket Security - SWARM erweitern durch eigene Security Behaviours
Wicket Security - JAAS Integration in Wicket Anwendungen