Softwaredesign Blogs

Michael Gerlinger
Wicket Security

Apache Wicket ist ein etabliertes Framework zur Erstellung von komponentenbasierten Webanwendungen. Die steigende Beliebtheit ist nicht zuletzt darauf zurückzuführen, dass Wicket den Entwicklern die Arbeit durch intelligente Konzepte sehr erleichtert. Einige dieser Konzepte sind die Trennung von Code und Markup, Testbarkeit durch UnitTests oder das nahezu vollständige Verbergen von JavaScript, so dass man ausschließlich in einer Programmiersprache entwickeln muss.

Auch im Rahmen der Security bringt Wicket bereits ein integriertes Konzept mit. Unser Fachartikel „Auf Nummer sicher –  Webanwendungen mit Apache Wicket“ im JavaMagazin Ausgabe 10/2010 beschreibt Teile des WicketSecurity Konzeptes und Möglichkeiten, es zu erweitern oder den eigenen Bedürfnissen anzupassen. Im Rahmen des Artikels wird auf unterschiedliche Schwachstellen eingegangen. Eine Beschreibung der häufigsten Schwachstellen bietet zum Beispiel das Open Web Application Security Projekt in seiner Top Ten . Einige Aspekte werden in eigenen Blogeinträgen detailliert betrachtet und anhand von Beispielimplementierungen vorgestellt.

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

Michael Gerlinger
Wicket Security - Schutz vor SQL Injection durch Validatoren

SQL Injection ist derzeit eine der weitverbreitesten Sicherheitslücken in Webanwendungen. Das Open Web Application Security Project (www.owasp.org) stuft das Injizieren von interpretierbarem Code auf Platz eins der häufigsten Sicherheitslücken ein. Eine Injection-Sicherheitslücke entsteht dann, wenn es einem Angreifer gelingt, Code in eine Anwendung einzuschleusen und in einem Interpreter innerhalb der Anwendung auszuführen. Dadurch ist es möglich, unerlaubten Zugriff auf Daten zu bekommen oder bestehende Daten der Anwendung zu manipulieren. Häufig sind die Backendsysteme der Anwendung das Angriffsziel von InjectionFlaws, unabhängig davon, um welche Technologie es sich handelt. Codefragmente können in SQL, JPQL, xPath Abfragen, LDAP Abfragen oder Betriebssystem Kommandos eingeschleust und interpretiert werden.

In diesem Blogbeitrag wird exemplarisch beschrieben, wie eine Wicket Anwendung durch das in Wicket integrierte Konzept der Validatoren oder Konverter vor SQL Injection geschützt werden kann. Da die Implementierung der Validierungslogik sehr komplex werden kann, nutzen wir zu Unterstützung die OWASP Enterprise Security API (ESAPI). ESAPI bietet eine kostenlose OpenSource Bibliothek mit Funktionalitäten, die helfen, Webanwendungen sicherer zu implementieren.

Als Maßnahmen gegen (SQL) Injection wird empfohlen, Technologien oder APIs zu nutzen, welche keine Interpreter verwenden. Eine Alternative sind parametrisierbare Schnittstellen wie z.B. prepared Statements, die in den Abfragesprachen der Perdsistenzframeworks geboten werden (JPQL, SQL).

Da nicht alle Backendsysteme sichere Schnittstellen zur Verfügung stellen, ist es notwendig, Eingaben zu validieren oder umzuwandeln, um (SQL) Injection zu verhindern. Apache Wicket bietet die Möglichkeit, an jedem Formularfeld Konverter und Validatoren zu definieren. Wird ein Formular übermittelt, werden im Rahmen des RequestCycles für jedes Formularfeld zuerst die Konverter und dann die Validatoren ausgeführt. Erst wenn beide erfolgreich durchlaufen wurden, werden die Daten in das Model übernommen und stehen dem Entwickler für weitere Aktivitäten zur Verfügung.

Ein spezieller Validator kann dazu verwendet werden, die Eingaben nach ungewünschtem Code zu überprüfen. Dieses Vorgehen ist als Blacklisting bekannt. Dabei  wird über Definitionen festgelegt, welche Zeichenketten nicht akzeptiert werden. Bei Blacklisting- Ansätzen besteht immer die Gefahr, dass Schlüsselworte vergessen werden. Als alleiniges Sicherheitskonzept sind sie deshalb nicht ausreichend. Als Ergänzung zu anderen Konzepten können Blacklist Validatoren dennoch dabei helfen, gefährlichen Input auszusortieren. Das folgende Beispiel zeigt die Implementierung eines Validators, der über RegularExpresions bekannte SQL Schlüsselworte erkennt und daraufhin einen Fehler ausgibt.

Hier werden exemplarisch die Schlüsselworte „or“ und „union“ sowie Zeichen zum beenden bzw. abschneiden von SQL-Querys erkannt.

public class ExampleSQLInjectionValidator extends StringValidator {
 List patterns = new ArrayList();

 public ExampleSQLInjectionValidator() {
  //pattern zur erkennung von sql metazeichen um einen query zu
  //beenden
  patterns.add(Pattern.compile(".*(([-]{2})|(\\%3B)|(;)|#).*"));
  // erkennung von OR injection
  patterns.add(Pattern.compile("\\w*((\\%27)|('))?((\\%6F)|o|O|
            (\\%4F))((\\%72)|r|R|(\\%52)).*"));
  // erkennung von UNION injection
  patterns.add(Pattern.compile("\\w*((\\%27)|('))?((\\%55)|u|U
            (\\%75))((\\%4E)|n|N|(\\%6E))
            ((\\%49)|i|I|(\\%69))((\\%6F)
            |o|O|(\\%4F))((\\%4E)|n|N|
            (\\%6E)).*"));
 }

 @Override
 protected void onValidate(IValidatable validatable) {

  // Check value against pattern
  for (Pattern pattern : patterns) {
   if(pattern.matcher(validatable.getValue()).matches())    {
    error(validatable);
   }
  }
 }

 }

Als Quelle für weitere RegularExpressions kann das OWASP ModSecurity Core Rule Set Project  dienen. In diesem Projekt werden Regeln für das Apache Web Server Modul mod_security definiert. Dieses Modul prüft den Input des Webservers. Die Regeln dieser Prüfungen basieren auf RegularExpressions, welche auch in einen PatternValidator integriert werden können.

Statt über Blacklisting unerwünschten Input auszusortieren, ist der sicherere Weg, für jedes Textfeld explizit festzulegen, welcher Input erwartet wird. Dieses Vorgehen wird als Whitelisting bezeichnet. Für Whitelisting Validierung können ebenfalls Wicket-Validatoren definiert werden. Unterstützung bei der Validierung von erwarteten Input bietet Wicket über eine Vielzahl fertig einsatzbereiter Validatoren, beispielsweise zur Überprüfung von Datumseingaben, Zeichenketten, Zahlen, etc. . OWASP bietet über das Validator Interface der ESAPI Bibliothek ebenfalls eine breite Unterstützung bei der Inputvalidierung. Diese kann dann in eigenentwickelte Validatoren integriert werden. Das folgende Beispiel zeigt einen Wicket-Validator, der mit Hilfe des ESAPI-Validator überprüft, ob es sich um eine valide Kreditkartennummer handelt.

public class ESAPIValidator extends StringValidator {
  @Override
  protected void onValidate(IValidatable<String> validatable) {
    ESAPI.validator().isValidCreditCard("creditcard_input",
    validatable.getValue(), true);
  }
}

Validatoren können über die add(IValidator) Methode zu einer FormComponent hinzugefügt werden.

text.add(new ExampleSQLInjectionValidator());

Über Vererbung oder Komposition (Wicket Behaviors) können solche Querschnittsaspekte auch zentral definiert werden.

Wicket- und ESAPI-Validatoren stellen ein umfangreiches Hilfsmittel zur Verminderung der Gefahr von SQL Injection dar.

ESAPI kann über Maven in die Anwendung eingebunden werden

Da ESAPI derzeit in keinem öffentlichen Repository zur Verfügung steht, muss die Bibliothek heruntergeladen und im lokalen – bzw. Unternehmensrepository installiert werden.

mvn install:install-file -Dfile=ESAPI-2.0_rc6.jar -DgroupId=OWASP
-DartifactId=ESAPI -Dversion=2.0rc6 -Dpackaging=jar

Wird ESAPI über die pom.xml des Projektes geladen, werden alle transitiven Abhängigkeiten automatisch hinzugefügt.

<dependency>
   <groupId>OWASP</groupId>
   <artifactId>ESAPI</artifactId>
   <version>2.0rc6</version>
</dependency>

Abschließend muss noch die Datei ESAPI.properties in die Verzeichnisse src/main/resources und src/test/resources kopiert werden. Die Datei wird zusammen mit dem jar File heruntergeladen.

Eine Eigenschaft von Validatoren ist, dass die Daten nur nach erfolgreicher Validierung in das Model übernommen werden. Schlägt die Validierung fehl, wird mit einer Fehlermeldung abgebrochen. Bei dem Einsatz von Validatoren ist es nicht vorgesehen, Daten zu verändern und dann zu übernehmen.
Ist es gewünscht, die Eingaben zu bereinigen und dann ins Modell zu übernehmen, kann dies über einen Konverter erreicht werden. In diesem Konverter kommt das Encoder Interface der ESAPI Bibliothek zum Einsatz. Bei der Encodierung von SQL Syntax werden SQL spezifische Zeichen umgewandelt.

public class OracleConverter implements IConverter {
      public Object convertToObject(String value, Locale locale{
            String converted;
            Encoder encoder = ESAPI.encoder();
            converted=encoder.canonicalize(value,true);
            converted = encoder.encodeForSQL(newOracleCodec(),
                        value);
            return converted;
      }
      public String convertToString(Object value, Locale locale) {
            return value.toString();
      }
}

Nahezu jeder Hersteller von Datenbankmanagementsystem hat einen eigenen SQL Dialekt für sein Produkt. Dieser Dialekt legt die SQL-Syntax für Abfragen fest. Daher muss angegeben werden, für welchen SQL-Dialekt Sonderzeichen encodiert werden sollen. ESAPI bietet derzeit Codecs für MySQL und Oracle Syntax an.

Um einen speziellen Converter für eine Component zu definieren, kann die getConverter Methode überschrieben und der gewünschte Converter zurückgegeben werden.
Da Wicket für Components, welche mit String typisiert wurden, (TextField<String>) keine Converter aufruft, muss die Methode convertInput() auch überschrieben werden.

final TextField<String> text = new TextField<String>("text"
           ,newModel()){
      @Override
      public IConverter getConverter(Class<?> type) {
          return new OracleConverter();
      }
     @Override
      protected void convertInput() {
          finalIConverter converter = getConverter(getType());
          setConvertedInput((String) converter.convertToObject
          (getInput(), getLocale()));
      }
};

In diesem Blogeintrag wurde gezeigt, wie man mit den Wicket-Konzepten der Validatoren und Konvertern sowie der OWASP ESAPI eine Anwendung auf einfache Weise gegen Injection Schwachstellen schützen kann.

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

Michael Gerlinger
Wicket Security - Keine CSRF Angriffe dank Security URL-Parameter

Cross Side Request Forgery oder auch Session Riding bezeichnet einen Angriff, bei dem ein Angreifer versucht, einen Benutzer dazu zu bringen, manipulierte Anfragen an eine Webanwendung zu senden. Dabei wird der Browser des Anwenders verwendet und damit die Aktion unter dessen Identität und mit dessen Privilegien ausgeführt.

Um diesen Angriffsvektor zu verdeutlichen, hier ein kleines Beispiel: In einem privaten Heimnetzwerk steht ein Router mit integriertem DSL-Modem. Der Router stellt eine Webanwendung zur Konfiguration bereit. Innerhalb dieser Konfigurationsanwendung gibt es eine Schaltfläche, um den Router in den Auslieferungszustand zurückzusetzen. Alle eigenen Einstellungen sowie die DSL Zugangsdaten gehen dabei verloren. Die Schaltfläche zum zurücksetzen ist als einfacher Link realisiert:

<a href="/konfig/reset/"> Auf Firmeneinstellung zurücksetzen</a>

Bei Auslieferung hat der Router die IP-Adresse 192.168.1.1. Ein Angreifer platziert nun ein einem Hilfeforum für exakt diesen Router einen Post, in dem er ein Bild einbindet.
<img src=“192.168.1.1/konfig/reset/“>
Beim Aufruf des Posts im Forum passiert nun folgendes: Der Browser versucht das Bild zu laden und ruft die angegebene URL auf. Da es sich um eine Hilfeforum des angreifbaren Routers handelt, besteht eine hohe Wahrscheinlichkeit, dass der Betrachter diesen Typ Router verwendet. Ist die Werksseitig eingestellte IP-Adresse des Routers nicht geändert worden, ruft der Betrachter ohne es zu wissen die „reset“ Funktion seines Routers auf. Das ist dann problematisch, wenn er in einem anderen Browserfenster noch an der Konfigurationsanwendung des Routers angemeldet war. Auch hier erhöht der Post in einem Hilfeforum die Wahrscheinlichkeit, dass parallel versucht wird, ein Problem mit dem Router zu lösen.

Apache Wicket bietet einige Möglichkeiten, die Gefahr von CSRF Angriffen zu verringern. Zum einen referenzieren die URLs nicht auf konkrete Aktionen oder Seiten, sondern beinhalten Informationen, die von dem Framework ausgewertet werden. Wohin ein Link verweist ist damit immer abhängig vom Zustand und der Version der Anwendung bzw. der jeweiligen WicketSession. Diese schlecht interpretierbaren URLs erschweren die Durchführung von CSRF Angriffen, allerdings beseitigen sie die Gefahr nicht vollständig. Die Wicket Entwickler schlagen als Gegenmaßnahme vor, die URLs der Webanwendung zu verschlüsseln. Eine Manipulation wird damit unmöglich gemacht.
Als serverseitige Gegenmaßnahme für CSRF ist es auch möglich, eine wechselnde, nicht vorhersehbare Zeichenkette in den Request des Browsers einzufügen, die geprüft wird, wenn ein Request wieder beim Server ankommt. Damit kann gewährleistet werden, dass alle eingehenden Requests auch von der Webanwendung selbst erzeugt wurden, da nur diese die Zeichenkette kennt. Ein Angriff auf willkürliche Opfer, wie im Beispiel beschrieben, wird dadurch verhindert.
In dem oben genannten jira-Eintrag wird eine Lösung vorgeschlagen, die ein Formular bereitstellt, welches jedem Request ein verstecktes Formularfeld mit einer zufälligen Zeichenkette hinzufügt. Die selbe Zeichenkette wird auch noch einmal als Cookie an den Request angefügt.

 public class SecureForm extends Form {
  private final static Logger log = LoggerFactory
          .getLogger(SecureForm.class);
  private static final Random random;
  static {
   try {
      random = SecureRandom.getInstance("SHA1PRNG");
    } catch(NoSuchAlgorithmException e) {
      throw new RuntimeException(e);
   }
  }

  private static String token() {
    long r = random.nextLong();
    if (r < 0)
        r = -r;
    return Long.toString(r, 36);
  }

  private String csrfProtection() {
    Cookie cookie = ((WebRequest) getRequest())
            .getCookie("csrfProtection");
    if (cookie == null) {
       cookie = new Cookie("csrfProtection", token());
      cookie.setPath("/");
      cookie.setSecure(true);
       ((WebResponse) getResponse()).addCookie(cookie);
    }
    return cookie.getValue();
  }

  public SecureForm(String id) {
    this(id, null);
  }

  public SecureForm(String id, IModel model) {
    super(id, model);
    add(new HiddenField("csrf-protection"
      , new Model(csrfProtection()))
      .setRequired(true)
      .add(new IValidator() {
        public void validate(IValidatable validatable) {
          if (!validatable.getValue().toString()
                    .equals(csrfProtection())) {
            log.warn("potential csrf attack, submitted value: " +
              validatable.getValue());
            validatable.error(new ValidationError().setMessage(
                          "missing csrf protection cookie"));
          }
        }
      }));
    }
  }

Da der Angreifer keine Kontrolle über den Rechner des Anwenders hat, ist es ihm nicht möglich, die zufällige Zeichenkette für diesen Nutzer auszulesen. Weder das Cookie, noch der Wert im versteckten Formularfeld ist dem Angreifer bekannt. Er müsste also den korrekten Wert erraten, um einen Request mit manipuliertten Formularinhalten unter der Identität des Anwenders absenden zu können.

Diese Variante setzt einen Security Parameter nicht direkt in die URL des Request, sondern überträgt ihn im Request Header. Um den Parameter direkt in die URL zu integrieren, muss eine eigene Implementierung der IRequestCodingStrategy geschrieben werden. Eine Erweiterung der standardmäßig von Wicket verwendeten WebRequestCodingStrategy ist nicht möglich, da die Methoden, encode und decode, die erweitert werden müssten, durch final Deklarationen vor dem Überschreiben geschützt sind.

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

Michael Gerlinger
Wicket Security - SWARM erweitern durch eigene Security Behaviours

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

Michael Gerlinger
Wicket Security - JAAS Integration in Wicket Anwendungen

Werden Wicket-Anwendungen in die bestehende IT Landschaft von Unternehmen integriert, stellt sich schnell die Frage nach der Wiederverwendung bestehender Authentifizierungs- oder Autorisierungslösungen. Die Integration von Spring Security ist in diesem Blog sehr umfangreich beschrieben.  Mit der Integration von Apache Shiro befasst sich das Projekt wicket-shiro .

Dieser Blogeintrag beschreibt, wie sich der Java Authentication and Autorisation Service (JAAS) in eine Wicket Anwendung integrieren lässt, um beispielsweise bestehende LoginModule und CallbackHandler oder eigene Principal-Implementierungen wiederverwenden zu können.

Grundlage für die JAAS Integration stellt eine Anwendung dar, in die wicket-auth-roles integriert wurde. JAAS wird verwendet, um die Authentifizierung durchzuführen und die Rollen der angemeldeten Benutzer zu verwalten.

Wichtiger Bestandteil der Integration ist dabei die Wicket-Session. Für die Verwendung von wicket-auth-Roles ist die Session von AuthenticatedWebSession  abgeleitet. Es  müssen die Methoden:

/**
* Authenticates this session using the given username and password
*
* @param username
*            The username
* @param password
*            The password
* @return True if the user was authenticated successfully
*/
public abstract boolean authenticate(final String username, final String password);

/**
 * @return Get the roles that this session can play
 */

public abstract Roles getRoles();

implementiert werden.

Ein Beispiel für eine einfache Implementierung der Session:

import java.security.Principal;
import java.security.acl.Group;
import java.util.Enumeration;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import org.apache.wicket.Request;
import org.apache.wicket.authentication.AuthenticatedWebSession;
import org.apache.wicket.authorization.strategies.role.Roles;

public class JAASSession extends AuthenticatedWebSession {

    private Subject subject;
    public static final String ROLES_GROUP_NAME = "Roles";
    private LoginContext context;

    public EasyJAASSession(Request request) {
        super(request);
    }

    @Override
    public boolean authenticate(String username, String password) {
        boolean authenticated = false;

        try {
            context = new LoginContext("other",
               new MyUsernamePasswordHandler(username, password));
            context.login();
            subject = context.getSubject();
        } catch (LoginException e) {
            // Fehlerbehandlung
        }

        return authenticated;
    }

    @Override
    public Roles getRoles() {
        Roles roles = new Roles();
        if (subject != null) {
            for (Principal p : subject.getPrincipals()) {

                // Für dieses Beispiel müssen die Rollen beim
                // erfolgreichen Login dem Subject
                // als Group mit dem namen "Roles" hinzugefügt
                // werden. Das muss innerhalb des Login Moduls
                // geschehen.

                if ((p instanceof Group) && (ROLES_GROUP_NAME
                      .equalsIgnoreCase(p.getName()))) {
                    Group g = (Group) p;
                    Enumeration<? extends Principal> members =
              g.members();
                    while (members.hasMoreElements()) {
                        Principal member = members.nextElement();
                        roles.add(member.getName());

                    }
                }
            }
        }
        return roles;
    }

    @Override
    public void signOut() {
        super.signOut();
        try {
            if (context != null)
                context.logout();
        } catch (LoginException e) {
            // Fehlerbehandlung
        }
        subject = null;
    }

}

Wie die Rollen des angemeldeten Benutzers innerhalb des subjects verwaltet werden ist abhängig von der konkreten Implementierung der LoginModuls. Für das Beispiel wurde davon ausgegangen, dass die Rollen über eine Group in die principals des subject gespeichert wurden.    

Das Beispiel geht von einer einfachen Username Passwort Authentifizierung aus. Dies ist Vorgabe von wicket-auth-roles, kann aber erweitert werden.  Soll beispielsweise zur Authentisierung ein SSO-Token  verwendet werden, muss in der Session eine alternative authenticate-Methode zur Verfügung stehen.

public boolean authenticate(SSOToken myToken){
      boolean authenticated = false;

    try {
        context = new LoginContext("tokenbased"
                 , new MyTokenHandler(myToken));
        context.login();
        subject = context.getSubject();
    } catch (LoginException e) {
        // Fehlerbehandlung
    }
[...]
    return authenticated;
}

 

Das Token kann in einer entsprechenden LoginPage aus dem Request ausgelesen werden und dann an die Session zur Authentifizierung übergeben werden.

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

Zeige 1 - 5 von 15 Ergebnissen.
Elemente pro Seite 5
von 3