Archiv

Archiv für die Kategorie ‘JDeveloper’

IT-Security (Part 3): WebLogic Server and Java Security Features

WebLogic Server and Java Security Features [1]

WebLogic Server supports the Java SE and Java EE Security to protect the resources of whole system. The resources could be Web applications, Uniform Resource Locator (URL), Enterprise JavaBeans (EJBs), and Connector components.

Java SE capabilities: Security APIs

Java uses APIs to access security features and functionality and its architecture contains a large set of application programming interfaces (APIs), tools, and implementations of commonly-used security algorithms, and protocols. This delivers the developer a complete security framework for writing applications and enables them to extend the platform with new security mechanisms.[2]

Java Authentication and Authorization Services (JAAS)

WebLogic Server uses the Java Authentication and Authorization Service (JAAS) classes to consistently and securely authenticate to the client. JAAS is a part of Java SE Security APIs and a set of Java packages that enable services to authenticate and enforce access controls upon users and /or fat-client authentication for applications, applets, Enterprise JavaBeans (EJB), or servlets.

JAAS uses a Pluggable Authentication Module (PAM) framework, and permits the use of new or updated authentication technologies without requiring modifications to the application. Therefore, only developers of custom Authentication providers and developers of remote fat client applications need to be involved with JAAS directly. Users of thin clients or developers of within-container fat client applications do not require the direct use or knowledge of JAAS.

JAAS LoginModules

All LoginModules are responsible for authenticating users within the security realm (we are going to discuss about that later) and for populating a subject with the necessary principals (users/groups). LoginModules contains necessary methods for Login Context, Accounts, Credentials, configuration of them, and different ways to exception handling. Each Authentication providers will be configured in a security realm, its LoginModules will store principals within the same subject too. I try to present that with an example: Via WebLogic Server Admin Console: Home >myDomain > Domain Structure click on Security Realms and then create a new realm “Moh_Realm-0” and then click on “OK”

p3_realm_1

Figure 1 create a new Realm

Select new realm and then click on tab “provider”, and then click on “New”, in order to create a new provider:

p3_realm_2

Figure 2 open the new Realm

In this use case, we select type: “WebLogic Authentication Provider” and give a name e.g. “DefAuthN”, then “OK”.  The WebLogic Authentication provider is configured in the default security realm (myrealm). The WebLogic Authentication provider allows you to edit, list, and manage users, groups, and group membership. User and group information is stored in the embedded LDAP server.[3]

p3_AuthenticationProvider_3

 Figure 3 create a new Authentication Provider

After define “Provider”, we have to restart Admin Server. Now, we can check and compare users of new realm (Moh_Realm-0) with default realm (myrealm) of WebLogic. For myrealm, Icreated a new user named “userDOAG” and we see the following list there (Home >Summary of Security Realms >myrealm >Users and Groups)

p3_users_4

Figure 4 users of myrealm

But I didn’t create same user for Moh_Realm-0 (Home >DefAuthN>Summary of Security Realms >Moh_Realm-0 >Users and Groups):

p3_users_5

Figure 5 users of Moh_Realm-0

It shows, that we can use security provider in different gatherings und expand our security realm with additional user, groups, and security providers. We are working on it in next part of this article.

JAAS Control Flags

The JAAS Control Flag attribute determines how the LoginModule for the WebLogic Authentication provider is used in the login sequence. The values for the Control Flag attribute are as follows: Home >Summary of Security Realms > Moh_Realm-0 >Providers > DefAuthN

 p3_JAAS_ControlFlag_6

Figure 6 Control flags via Admin Consol

  • REQUIRED – This LoginModule must succeed. Even if it fails, authentication proceeds down the list of LoginModules for the configured Authentication providers. This setting is the default.
  • REQUISITE – This LoginModule must succeed. If other Authentication providers are configured and this LoginModule succeeds, authentication proceeds down the list of LoginModules. Otherwise, return control to the application.
  • SUFFICIENT – This LoginModule needs not succeed. If it does succeed, return control to the application. If it fails and other Authentication providers are configured, authentication proceeds down the LoginModule list
  • OPTIONAL – The user is allowed to pass or fail the authentication test of these Authentication providers. However, if all Authentication providers configured in a security realm have the JAAS Control Flag set to OPTIONAL, the user must pass the authentication test of one of the configured providers.[4]

Now, we can focus on two important JAAS-tasks: authentication and authorization of users…[5]

References


[4] Oracle Fusion Middleware: Understanding Security for Oracle WebLogic Server 12c Release 1, (12.1.1), E24484-02, January 2012: http://docs.oracle.com/cd/E24329_01/web.1211/e24484.pdf

JDeveloper QuickTip – Assigning more memory

Did you ever have the problem that JDeveloper crashes each day during your lunch break? Worry no more. It’s most likely a problem with too less memory.

JDeveloper memory settings are stored in $MIDDLEWARE_HOME/jdeveloper/ide/bin/ide.conf.

JDeveloper IDE configuration

Change the following lines to settings of your liking. A maximum heap size of around 1,5 GB seems to be a good setting if your working heavily with SOA projects (and have enough memory on your machine).


AddVMOption -Xmx640M
AddVMOption -Xms128M

Hope this helps to reduce your regular JDeveloper shutdowns and low memory warnings.

Kategorien:JDeveloper

OWSM Custom Assertion zur Absicherung einzelner Services per IP-Adresse

An diesem Beispiel soll die Erstellung einer OWSM (Oracle Web Services Manager) Custom Assertion vorgestellt werden. Die Custom Assertions erlauben es, nahezu beliebige Policies zu erstellen, die wie die von Oracle vorgefertigten Policies auf Service-Endpunkte, SOA Komponenten oder auch Service-Referenzen angewendet werden können. Typischerweise kümmern sich diese Policies um Authentifizierung und Autorisierung.

Unser Anwendungsfall: wir möchten einen bestimmten Service nur für bestimmte IP-Adressen zugreifbar machen. Die Vorstellung ist, dass wir eine Liste mit gültigen IP-Adressen für den jeweiligen Service konfigurieren. Alle Requests, die von anderen Adressen kommen, sollen abgelehnt werden.

Diese Funktionalität ist in der SOA Suite leider nicht Out-Of-The-Box vorhanden.

1. Projekt-Setup

Um das Projekt aufzusetzen wird in JDeveloper einfach ein Standard-Java-Projekt erstellt.

Bevor die Entwicklung starten kann, müssen einige Bibliotheken für OWSM und SOA in den Build-Pfad eingebunden werden. Die genaue Beschreibung spare ich mir an dieser Stelle – wer möchte kann jederzeit die aktuelle Liste aus dem fertigen Projekt (siehe unten) kopieren (Tipp: Einfach die .jpr-Datei mit einem Texteditor bearbeiten und sämtliche Library References rüberkopieren – nach einem Refresh in JDev, sind die Bibliotheken dort bekannt).

2. Grundstruktur der Assertion-Klasse

Grundsätzlich ist eine Custom Assertion lediglich eine einzige Klasse, die von oracle.wsm.policyengine.impl.AssertionExecutor erbt. Hier ist unser erstes Grundgerüst:

public class ClientIpAssertion extends AssertionExecutor {
    private final static Logger LOG = Logger.getLogger(ClientIpAssertion.class.getName());
 
    protected IAssertion mAssertion = null;
    protected IExecutionContext mEcontext = null;
    protected oracle.wsm.common.sdk.IContext mIcontext = null;

    public IResult execute(IContext iContext) {

       // Hier wird die Assertion ausgefuehrt
    }
 
    public void init(IAssertion iAssertion, IExecutionContext iExecutionContext, IContext iContext) {
        mAssertion = iAssertion;
        mEcontext = iExecutionContext;
        mIcontext = iContext;
    }
 
    public void destroy() {
    }
}

Die Methode init() wird vom OWSM zum Initialisieren aufgerufen. Hier kommen schonmal grundsätzlich einige Umgebungsobjekte mit, die später noch wichtig sind, um z.B. die Parameter auszulesen.

Die Methode destroy() wird beim Zerstören der Klasse aufgerufen. Falls man irgendwelche Ressourcen belegt hat, kann man diese hierin freigeben.

3. Metadaten

Neben der Implementierung der Assertion benötigt man noch eine XML-Datei (ClientIpAssertion.xml) mit einigen Metadaten zur Assertion.

<orawsp:AssertionTemplate xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy"
                          orawsp:Id="ClientIp"
                          orawsp:attachTo="generic" orawsp:category="security"
                          orawsp:description="Client IP assertion verifies the client IP address to be in a configured list of addresses"
                          orawsp:displayName="Client IP"
                          orawsp:name="custom/CientIp"
                          xmlns:custom="http://schemas.oracle.com/ws/soa/custom">
  <custom:custom-executor orawsp:Enforced="true" orawsp:Silent="false"
                   orawsp:category="security/custom"
                   orawsp:name="WSSecurity_Custom_Assertion">
    <orawsp:bindings>
      <orawsp:Implementation>com.opitzconsulting.clientipassertion.ClientIpAssertion</orawsp:Implementation>
      
      <orawsp:Config orawsp:configType="declarative" orawsp:name="ClientIp">
        <orawsp:PropertySet orawsp:name="clientip">
          <orawsp:Property orawsp:contentType="required"
                           orawsp:name="allowedIpAddresses" orawsp:type="string">
            <orawsp:Value>127.0.0.1</orawsp:Value>
          </orawsp:Property>
        </orawsp:PropertySet>
      </orawsp:Config>
    </orawsp:bindings>
  </custom:custom-executor>
</orawsp:AssertionTemplate>

Hierin wird z.B. die ID der Assertion festgelegt (hier: “ClientIp”), woran die Policy angehängt werden kann (hier: “generic”, sprich kann überall verwendet werden – man könnte es auch auf Service-Endpunkte, SOA Komponenten oder SOA Referenzen einschränken) und weitere allgemeine Infos wie ein Anzeigename, Beschreibung, usw.

Im Tag “orawsp:Implementation” wird der vollständige Name der Implementierungsklasse angegeben. Besonders interessant ist der nächste Abschnitt, der die möglichen Konfigurationsparameter der Assertion zusammen mit Standardwerten enthält. Hier: Ein Parameter “allowedIpAddresses” vom Typ “string” mit dem Standardwert “127.0.0.1″.

Diese Konfigurationsparameter können später im Enterprise Manager konfiguriert werden, wenn man sich aus den Assertions eine eigene Policy zusammenbaut (siehe Deployment).

4. IP-Vergleich

Kommen wir zum Kern der Assertion: Vergleich der Client IP Addresse mit einer Liste von erlaubten IP-Addressen. Da dieser Vergleich für jeden Aufruf ausgeführt werden muss, erfolgt die Implementierung vollständig in der execute()-Methode.

 public IResult execute(IContext iContext) {
        IResult result = new Result();
        result.setStatus(IResult.FAILED);
 
        // Abschnitt A
        IMessageContext.STAGE stage = ((IMessageContext)iContext).getStage();
        LOG.fine("stage=" + stage);
        if (stage != IMessageContext.STAGE.request) {
            LOG.fine("Nothing to process on this stage");
            result.setStatus(IResult.SUCCEEDED);
            return result;
        }
        
        // Abschnitt B
        SOAPBindingMessageContext soapbindingmessagecontext = (SOAPBindingMessageContext)iContext;
 

        String remoteAddress = soapbindingmessagecontext.getRemoteAddr();
        String[] allowedIpAddresses = new String[] { "127.0.0.1" };
 
        boolean clientIpValid = false;
        for (String allowedIpAddress : allowedIpAddresses) {
            if (allowedIpAddress.equals(remoteAddress)) {
                clientIpValid = true;
            }
        }
 
        // Abschnitt C
        if (clientIpValid) {
            result.setStatus(IResult.SUCCEEDED);
        } else {
            WSMException exception = new WSMException("Client IP address " + remoteAddress + " is not allowed");
            result.setFault(exception);
            result.setStatus(IResult.FAILED);
        }
 

        return result;
    }

Als allererstes initialisieren wir ein IResult-Objekt mit einem Fehlerstatus – per Default soll ein Fehler zurückkommen.

Im Abschnitt A geht es zunächst darum, zu prüfen, in welchem Stage wir uns befinden. Die Policy wird grundsätzlich für Request und Reply ausgeführt. Da für unsere Policy nur der Request Stage interessant ist geben wir für alle anderen Fälle ein SUCCEEDED zurück und beenden an dieser Stelle die Bearbeitung.

In Abschnitt B holen wir uns zuerst die Remote IP Addresse aus dem SOAPBindingMessageContext. Hinweis: Es könnte auch sein, dass hier kein SOAPBindingMessageContext vorliegt, falls der Aufruf nicht über ein SOAP Binding erfolgt, sondern z.B. über ein Direct Binding. Dieser Fall wird hier vernachlässigt.

Dann legen wir – vorerst hardcodiert – ein Array mit gültigen IP-Adressen ein. Trifft der Vergleich einer IP-Adresse dieser Liste mit der Remote-Adresse zu, so wird die Variable clientIpValid auf true gesetzt.

In Abschnitt C wird ein entsprechendes Result gesetzt auf Basis von clientIpValid. Interessant ist hier vor allem der Fehlerfall. Hier sollte man eine brauchbare Fehlerbeschreibung eintragen, da diese bei Fehlschlag an den Aufrufer zurückgesandt wird. Hinweis: Es gibt keinen Flow Trace und keine Composite Instance, falls eine der eingehenden Policies fehlschlägt – dadurch wird diese Fehlermeldung doppelt wichtig, wenn man nicht lange Zeit Logs durchwühlen möchte.

Die Assertion kann nun deployed werden und wird nur noch Requests von 127.0.0.1 durchlassen.

5. Parameter übergeben

Natürlich wollen wir die IP-Adressen nicht hardcodieren, vor allem, weil man dann für jede Änderung der IP-Adressen die komplette SOA Suite neustarten müsste – außerdem kann man die Assertion dann nicht wiederverwenden.

Wir haben den Parameter in den Metadaten oben bereits definiert. Nun brauchen wir also noch eine Möglichkeit, diesen in der Assertion auszulesen. Dazu verwenden wir folgendes Code-Schnipsel:

    private Properties configProps = new Properties(); 

    private void retrieveConfiguration() {
        IAssertionBindings bindings = ((SimpleAssertion)(mAssertion)).getBindings();
        if (bindings != null) {
            List<IConfig> cfgl = bindings.getConfigs();
            if (!cfgl.isEmpty()) {
                IConfig cfg = cfgl.get(0);
                List<IProperty> configProperties = cfg.getProperties();
                if (configProperties != null) {
                    for (IProperty configProperty : configProperties) {
                        String propName = configProperty.getName();
                        String propValue = configProperty.getValue();
                        if (propValue == null || propValue.trim().isEmpty())
                            propValue = configProperty.getDefaultValue();
                        if (propValue != null)
                            configProps.setProperty(propName, propValue);
                    }
                }
            }
        }
    } 

 

    public void init(IAssertion iAssertion, IExecutionContext iExecutionContext, IContext iContext) {
        mAssertion = iAssertion;
        mEcontext = iExecutionContext;
        mIcontext = iContext;
        retrieveConfiguration(); // Dieser Aufruf wurde hinzugefügt
    }

Diese Methode sollte am Besten aus der init()-Methode aufgerufen werden, da OWSM die init()-Methode immer aufrufen wird, wenn eine Änderung der Konfiguration erfolgt und sich somit die Policyversion erhöht.

Nun stehen alle Properties in dem privaten Property-Objekt configProps und können von dort verwendet werden. Da wir davon ausgehen, dass hier eine “,”-separierte Liste mit IP-Adressen drin steht, ersetzen wir unsere zuvor hardcodierte Liste durch folgendes:

     String[] allowedIpAddresses = 
                 ScenarioUtils.getConfigPropertyValue(
                     "allowedIpAddresses", 
                     soapbindingmessagecontext, 
                     configProps, 
                     null)
                 .split(",");

Und schon wird die konfigurierte Liste an erlaubten Adressen für die Prüfung herangezogen.

6. Deployment

Das Deployment erfolgt mit den folgenden Schritten:

  • JAR mit der Assertion in DOMAIN_HOME/lib kopieren
  • SOA Suite neustarten
  • Im EM unter Weblogic-Domain -> Web Services -> Policies -> Assertion Templates die Assertion importieren (ClientIpAssertion.xml)
  • Im EM unter Weblogic-Domain -> Web Services -> Policies eine neue Policy erstellen
  • In die Policy die Assertion “custom/ClientIp” einfügen und unten unter “Assertion-Inhalt” die Liste mit IP-Addressen vom Standard-Wert aus abändern

Nun kann die Policy analog anderer Sicherheitspolicies an Service-Endpunkte angehängt werden, die dann nur noch von bestimmten IP-Adressen aus aufgerufen werden können.

Zusammenfassung

Die Entwicklung eigener Policies ist immer dann hilfreich, wenn man in der SOA Suite eine bestimmte Anforderung in Bezug auf Security umsetzen möchte, die nicht Out-Of-The-Box geboten ist. Auf diese Weise haben wir beispielsweise auch eine Weitergabe der Authentifizierung im Payload realisiert, so dass unsere BPEL-(Geschäfts-)Prozesse frei von Authentifizierungsdetails bleiben.

Das komplette Projekt mit der oben erstellen Policy gibt es hier zum Download:
ClientIPAssertion.zip

Kategorien:JDeveloper, Oracle SOA Suite Schlagworte: , ,

HTTP Binding für namespacelose Elemente

In einem Kundenprojekt sollte ein System an die SAO Suite (11.1.1.5)
angeschlossen werden, das seine Nachrichten zwar als XML-Strukturen
per HTTP-POST verschickt, jedoch keinen Namespace für diese angibt.

Die Möglichkeit die einem hierzu wahrscheinlich als Erstes in den Kopf
kommt, das HTTP Binding, scheitert aber schon im Wizard mit folgender Meldung:

Fehlermeldung des HTTP Bindings bei namenlosen Schemata

Als Alternative den Socket Adapter zu verwenden oder ein Servlet vor das zu
erstellende Composite zu schalten klingt nur nach einer sehr mäßigen Lösung.

Durch gutes Zureden lässt sich das HTTP Binding dann aber doch zur Verarbeitung
von namenlosen XML-Elementen überreden.

Nachfolgend werden die hierzu nötigen Schritte beschrieben. Als Ausgangsbasis
dient dabei das unten aufgeführte Schema. Zu beachten ist, dass kein
Target Namespace oder Default Namespace angegeben ist.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="myElement" type="xsd:string"/>
</xsd:schema>

1. Target Namespace temporär hinzufügen
Um den Wizard zufriedenzustellen muss zunächst temporär das
targetNamespace-Attribut in die Schemadefinition eingefügt werden. Der
eingetragene Namespace ist hierbei nicht weiter wichtig.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://something.com">
  <xsd:element name="myElement" type="xsd:string"/>
</xsd:schema>

2. HTTP Binding Endpunkt erstellen
Jetzt kann im Wizard das Element zur Erzeugung des HTTP Binding
Endpunkts ohne Fehlermeldung ausgewählt werden.

3. Temporären Namespace wieder entfernen
Der eben hinzugefügte Namespace kann nun wieder entfernt werden.

4. WSDL des HTTP Binding Endpunkts anpassen
Da sich der Namespace des Schemas geändert hat, ist die generierte
WSDL des HTTP Binding Endpunkts ungültig geworden. In dieser muss
das Import-Element, wegen des fehlenden Namespaces, in ein
Include-Element geändert und das Namespaceprefix vor dem Message-Type
entfernt werden.

...
    <wsdl:types>
        <schema xmlns="http://www.w3.org/2001/XMLSchema">
            <include schemaLocation="schema.xsd"/>
        </schema>
    </wsdl:types>
    <wsdl:message name="myElement_msg_in">
        <wsdl:part name="myElement" element="myElement"/>
    </wsdl:message>
...

5. Deployment und Test
Der HTTP Binding Endpunkt sollte nun mit Nachrichten ohne Namespace
aufrufbar sein. Die Testkonsole im EM quittiert an dieser Stelle ihren
Dienst zwar mit einer SoapTestException, normale HTTP-POST
Nachrichten, etwa per curl, werden jedoch korrekt verarbeitet.

Nachfolgend noch zwei Screenshots aus dem EM.

Ablauf im EM

Die Nachricht ist im EM erkennbar:
Nachricht im EM

6. Viel Spaß damit haben

JDeveloper QuickTip – Output Console

Ever wondered, where JDeveloper puts its output? It actually prints it on the console. But usually this console is hidden in a Windows environment if you use the pre-installed link.

However it’s quite easy to enable. The pre-installed link points to YOUR_MIDDLEWARE_HOME\jdeveloper\jdeveloper.exe. Just change it (or create another link) to point to YOUR_MIDDLEWARE_HOME\jdeveloper\jdev\bin\jdev.exe – et voilà – you will now see a console window where JDeveloper puts its (sometimes helpful) output.

JDeveloper Output Console

Kategorien:JDeveloper Schlagworte: ,
Follow

Erhalte jeden neuen Beitrag in deinen Posteingang.