Pages

Friday, August 26, 2011

Single Sign On with windows / kerberos on WebLogic

In this blogspot I will show you the steps I did to achieve SSO kerberos windows authentication on an ADF or a Web Application deployed on a WebLogic application server.

Before we can start you should know the supported encryption types of your Windows Environment. For example Windows XP or Windows 2003 Domain Controller ( not SP1 ) does not support every encryption type.

I got this working with a Windows 7 client and a Windows 2008 R2 Domain Controller and my encryption type is RC4-HMAC-NT, which is also supported in Java 1.6

My Active Directory domain = ALFA.LOCAL  ( always use it in uppercase )

Make sure that all server can be found in the DNS ( and reverse )  and that the time is synchronized on all machines.

We start by creating a unique service account ( it must not exists, not as computer and not as an user ), in my case is that soaps3_kerb.


I used Welcome01 as password and make sure that the password never expires.


On the Windows 2008 DC server I did the following to generate a service account called HTTP/soaps3.alfa.local and map this to soaps3_kerb AD account. soaps3 is the server name of the WebLogic Server.


First generate a keytab file for the HTTP/soaps3.alfa.local@ALFA.LOCAL account,  HTTP is a container ( IIS also uses this convention ) and ALFA.LOCAL is my AD domain.

ktpass -princ HTTP/soaps3.alfa.local@ALFA.LOCAL -pass Welcome01 -mapuser soaps3_kerb@ALFA.LOCAL -out c:\soaps3.keytab -ptype KRB5_NT_PRINCIPAL -crypto RC4-HMAC-NT

my output
Targeting domain controller: AD-WIN2008R2.alfa.local

Using legacy password setting method
Successfully mapped HTTP/soaps3.alfa.local to soaps3_kerb.Key created.
Output keytab to c:\soaps3.keytab:
Keytab version: 0x502
keysize 68 HTTP/soaps3.alfa.local@ALFA.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x17 (RC4-HMAC) keylength 16 (0x1d863479e1ab3bd62a2bfafa1abaa2dd)


copy the generated soaps3.keytab file to the WebLogic machine. I put it in the c:\oracle folder.

Now we need to modify the Service Principal Names with the SPN utility.
setSpn -A HTTP/soaps3.alfa.local@ALFA.LOCAL soaps3_kerb

my output
Registering ServicePrincipalNames for CN=soaps3_kerb,CN=Users,DC=alfa,DC=local
        HTTP/soaps3.alfa.local@ALFA.LOCAL
Updated object



Now we can continue with the WebLogic Server configuration.

Start by making create a text file called krb5.ini and put it in c:\windows
ALFA.LOCAL is my AD domain and soaps3 is my WebLogic server and it exists in the alfa.local dns domain.  ad-win2008r2.alfa.local is my domain controller.
-------------------

[libdefaults]
default_realm = ALFA.LOCAL
default_tkt_enctypes = rc4-hmac
default_tgs_enctypes = rc4-hmac
permitted_enctypes = rc4-hmac

[domain_realm]
.soaps3.alfa.local = ALFA.LOCAL
soaps3.alfa.local = ALFA.LOCAL
.alfa.local = ALFA.LOCAL
alfa.local = ALFA.LOCAL

[realms]
ALFA.LOCAL = {
kdc = ad-win2008r2.alfa.local
admin_server = ad-win2008r2.alfa.local
default_domain = alfa.local
}
[appdefaults]
autologin = true
forward = true
forwardable = true
encrypt = true

---------------

On the soaps3 WebLogic machine we need to create a new Kerberos ticket which will be used by WebLogic.

First let's flush the current ones
go to c:\ ( not in the java bin folder )
klist purge

go to the bin folder of your java home ( jdk )
cd c:\oracle\jrockit-jdk1.6.0_26-R28\bin

kinit HTTP/soaps3.alfa.local@ALFA.LOCAL

My output
Password for HTTP/soaps3.alfa.local@ALFA.LOCAL:
New ticket is stored in cache file C:\Users\admin\krb5cc_admin


This should work and it will use the krb5.ini located at c:\windows.


Create or change an application with ADF Security or a normal Web Application which got security enabled. Open the web.xml and change the auth-method to CLIENT-CERT


  <login-config>
    <auth-method>CLIENT-CERT</auth-method>
  </login-config>


Deploy the application to the WebLogic Server.

Open the WebLogic console application and go to myrealm security realm -&gt; providers -&gt; authentication.

create a NegotiateIdentityAsserter called Microsoft.


Open the NegotiateIdentityAsserter and go to Provider Specific and de-select Form Based Negotiation Enabled.

Next step is to create a kerberos login configuration which will be read by WebLogic.
Create a text file called kerberos.login located in the c:\oracle. This is the content which will work with Java 1.6
-------

com.sun.security.jgss.krb5.initiate {
     com.sun.security.auth.module.Krb5LoginModule required
     principal="HTTP/soaps3.alfa.local@ALFA.LOCAL"
     useKeyTab=true
     keyTab="c:/oracle/soaps3.keytab"
     storeKey=true
     debug=true;
};

com.sun.security.jgss.krb5.accept {
     com.sun.security.auth.module.Krb5LoginModule required
     principal="HTTP/soaps3.alfa.local@ALFA.LOCAL"
     useKeyTab=true
     keyTab="c:/oracle/soaps3.keytab"
     storeKey=true
     debug=true;
};
-------

Add the following parameters to the EXTRA_JAVA_PROPERTIES in the setDomainEnv.bat of your domain.
-Dsun.security.krb5.debug=true 
-Djavax.security.auth.useSubjectCredsOnly=false 
-Djava.security.auth.login.config=C:/oracle/kerberos.login 
-Djava.security.krb5.realm=ALFA.LOCAL 
-Djava.security.krb5.kdc=ad-win2008r2.alfa.local 


We are finished with the WebLogic and the AD configuration.

Just add the login name of the window user and its groups to the myrealm security realm, so you can test the Web Application.

Log on a machine which is part of your AD domain.

use Internet Explorer and trust the weblogic site and enable authentication in the advanced options of IE.
or
use Google Chrome and start chrome.exe with the following parameter --args --auth-server-whitelist="*alfa.local" This allows SSO with chrome.


Monday, August 22, 2011

Do SAML with OWSM

In this blogpost I will explain the different SAML options and the advanced configurations you can do when you use the SAML client and server policies of Oracle Web Service Manager FMW 11gR1.
The following will be explained and configured in this blogpost.
  • A basic SAML authentication with 2 OWSM Servers.
  • Change the default SAML issuer name.
  • Allow only trusted SAML clients.
  • SAML Identity switching.
  • Virtual Users with User roles.
Creating a working SAML setup. 
For this we need two WebLogic domains and both have at least the Enterprise Manager web application and enabled the OWSM option. For this demo I will have one domain with SOA Suite and one with only a WebLogic Adminserver where we will deploy a JAX-WS Web Service which has an OWSM server policy. You can replace the SOA Suite with a OSB server ( it works in the same way ) . For OWSM, every domain need to have it's own MDS repository to store all the OWSM policies and for SOA Suite you also need a soa-infra database repos.

This will be our setup.
  • A client ( soapUI or WS client proxy ) calls an exposed web service of a SOA Suite composite and the client needs to provide a username token.
  • The exposed service has oracle/wss_username_token_service_policy as OWSM Server policy. The username token will be validated by WebLogic and the username will be passed on by SAML and signed with the signing certificate of the SOA Suite OWSM. The exposed service has a wire to a Mediator with a simple routing rule.
  • The Mediator has a wire to the Reference Web Service. This reference WS binding has oracle/wss11_saml_token_with_message_protection_client_policy as OWSM client policy.
  • The Reference WS binding calls a JAX-WS Web Service deployed on the other WebLogic Domain and this Web Service has oracle/wss11_saml_token_with_message_protection_service_policy as OWSM server policy. OWSM will validate the SAML issuer and check if it knows the username ( the password does not matter, because it is trusted )
The SOA Composite I used.

The JAX-WS service
Before we can test this SAML service, we need to generate some keystores, configure OWSM and add some users to WebLogic.
Execute the following commands to generate some self signed private keys and exchange the public keys ( this will trust each other certificates )

Go to the bin folder of your JDK.
cd c:\oracle\jrockit-jdk1.6.0_26-R28\bin

Generate a certificate for SOA ( server.jks ) and one for the JAX-WS server (  saml.jks )
keytool -genkey -alias serverKey -keyalg "RSA" -sigalg "SHA1withRSA" -dname "CN=server, C=US" -keypass welcome -keystore c:\temp\server.jks -storepass welcome -validity 3650
keytool -genkey -alias samlKey -keyalg "RSA" -sigalg "SHA1withRSA" -dname "CN=saml, C=US" -keypass welcome -keystore c:\temp\saml.jks -storepass welcome  -validity 3650

Export the public key
keytool -exportcert -alias serverKey -storepass welcome -keystore c:\temp\server.jks -file c:\temp\server.cer
keytool -exportcert -alias samlKey -storepass welcome -keystore c:\temp\saml.jks -file c:\temp\saml.cer

Import the keys in each other keystore ( for the trust (
keytool -import -alias serverKey -file c:\temp\server.cer -storepass welcome -keystore c:\temp\saml.jks
keytool -import -alias samlKey -file c:\temp\saml.cer -storepass welcome -keystore c:\temp\server.jks

Show the certificates in each keystore.
keytool -list -storepass welcome -keystore c:\temp\server.jks
keytool -list -storepass welcome -keystore c:\temp\saml.jks

Copy the server.jks to the config\fmwconfig folder of your SOA Suite domain. Do the same for the saml.jks keystore but then to fmwconfig of the JAX-WS server domain.

Go the Enterprise Manager (EM) application of the SOA Suite.  Open the WebLogic Domain treenode and select your SOA domain. In the Domain menu (right window)  go to Security -&amp;gt; Security Provider Configuration. Click on the Configure button in the keystore section.

  
Use ./server.jks in the Keystore Path field and serverKey in the Key and Crypt Alias. Use welcome for all the password fields.

We need to do the same at the JAX-WS server but then use the following values.
Use ./saml.jks in the Keystore Path field and samlKey in the Key and Crypt Alias. Use welcome for all the password fields.

Add a user with client as name and with weblogic1 as password in the myrealm security realm of the SOA Suite server. Do the same at the JAX-WS server but now use welcome1 as password.

Do a restart of the all the servers.

We can test the SAML setup by generating a Web Service Client proxy in JDeveloper. Here is an example how I add the client credentials.

that is all for the basic SAML test.

How to change the SAML issuer name. 
The default SAML issuer name is www.oracle.com , We can change this at the JAX-WS server. For this we need to go the EM application of the JAX-WS Server. Open the WebLogic Domain treenode and select your JAX-WS domain. In the Domain menu (right window)  go to Security -> Security Provider Configuration. Click on the Configure button in the Advanced section.

Here we can change the name attribute of saml.trusted.issuers.1 property to www.amis.nl and click on Ok. This way you will change the default trusted issuer for all the SAML login modules, if you only want to change this for SAML1.1 and not for SAML2 then you can open the saml.loginmodule instead (located at the Security Provider Configuration) and change it there. This will add an extra saml property name beside the one of www.oracle.com
You will need to restart the WebLogic server.

We also need to change an attribute on the reference web service binding of the SOA Composite. Select the reference binding and right click, to open the Configure WS Policies menu.

Click on the pencil to override the saml.issuer.name and use www.amis.nl

Deploy the composite and re-test it with the jdeveloper ws proxy client.

Allow only trusted SAML clients
In the current setup each public key found in the saml.jks keystore can sign a SAML token. In this part we can restrict this to only "CN=server, C=US", this is the DN of the signing certificate located at the SOA Suite server.

Go the Enterprise Manager (EM) application of the JAX-WS Server.  Open the WebLogic Domain treenode and select your JAX-WS domain. In the Domain menu (right window)  go to Web Services -> Platform Policy Configuration.

Go to the Trusted SAML clients Tab and add a new Trusted Issuer called www.amis.nl .
Select the just created Trusted Issuer and add a Trusted SAML Client and use CN=server, C=US as value.

Restart the JAX-WS Server and now only CN=server, C=US can sign the SAML token.

SAML Identity switching
In the last part of this blogpost we will change the identity of the SAML token. In the previous examples we used client as username and this is passed on to the JAX-WS server.  We will override this on the SOA Suite server.  In our test client we can now use weblogic as username and override to client in the SOA Composite.
Open the Mediator of the  SOA Composite where we will add an Assign to the request part of the Routing Rule.

Here we need to add the javax.xml.ws.security.auth.username property with client as value.

We also need to change the OWSM client policy to oracle/wss11_saml_token_identity_switch_with_message_protection_client_policy on the reference web service binding.

Deploy your composite.

Too bad, this is not enough we also need to give my SOA Composite the right permissions to do identity switching. Go the Enterprise Manager (EM) application of the SOA Suite.  Open the WebLogic Domain treenode and select your SOA domain. In the Domain menu (right window)  go to Security -> System Policies.

Select Codebase as Type and search. Select a Codebase policy and do Create Like.

Use file:${common.components.home}/modules/oracle.wsm.agent.common_11.1.1/wsm-agent-core.jar as value in the Codebase field and click on Edit.

Enter oracle.wsm.security.WSIdentityPermission in the Permission Class field. The action is always assert. The Resource Name is your Composite Name which does the identity switching.


Virtual Users with User roles
The last part is virtual users, in this section will we add some roles and change some attributes on the SOA Suite client user. Change the policy back on the composite reference ( oracle/wss11_saml_token_with_message_protection_client_policy ) and also use client as username in the web service proxy client.

First change some client user attributes. We can do this in the security realm of the SOA Suite WebLogic Domain.


Normally the user is only mapped to the user located at the JAX-WS server. To make virtual servers work we need to add a property to the saml.loginmodule located at the JAX-WS server.  For this we need to go the EM application of the JAX-WS Server. Open the WebLogic Domain treenode and select your JAX-WS domain. In the Domain menu (right window)  go to Security -> Security Provider Configuration.

Click on Edit and add a custom property oracle.security.jps.assert.saml.identity with value true.


Restart the JAX-WS WebLogic server.

We also need to do something in the SOA Composite.
Override the following properties

user.attributes with value  displayname,employeenumber ( use , to separate ldap attributes you want to pass on )
user.roles.include with value true
subject.precedence with value true

Deploy the composite and when you test your test client. You will see the following output on the JAX-WS Server.


virtual found
saml issuer: www.amis.nl

SAML attribute: employeenumber
value: 100

SAML attribute: Roles
value: Operators
value: AdminChannelUsers
value: IntegrationOperators
value: IntegrationMonitors
value: Monitors

SAML attribute: displayname
value: SAML client





Saturday, August 13, 2011

Contract First web service with JDeveloper

In this blogpost I will explain the options you have when you use JDeveloper to generate a web service based on a WSDL, so called top down or contract first. In my previous blogpost I showed you the bottom up approach. This works great but it can lead to a ugly WSDL which it is not so great for interoperability. Off course you can control it all with some web service annotations but then you really need to know what you are doing.

Here is an example of a bottom up WSDL. It matches with the java methods

Let's change it to this and use this WSDL in JDeveloper.

Before we can start lets copy the WSDL and its XSD to the project folder. This way JDeveloper can detect it.

In JDeveloper we can choose for Java Web Service from WSDL.

We can select our WSDL from the listbox and in this dialog we can choose for some important options.

First we can choose Java or for EJB 3.0 as Service Type. With Java as Service Type JDeveloper will add the Web Service as servlet to the web.xml. This is not the case with EJB.
With EJB as Service Type you will get transaction, security support, can use interceptors and the timer service. If you enable the Add Service Endpoint Interface option and add an Remote annotations to this interface you can call the Remote interface of this EJB with RMI (t3:) besides invoking this Web Service with HTTP.

The Service Endpoint Interface (SEI) is a Java interface that declares the methods that a client can invoke on the service. It provides the client's view of the web service and hiding the implementation from the client.



Provide the package names for the web service and the java types.

This will generate the following code. We need this JAXB code in completing the service implementation.  

The generated service interface.

The service implementation.

To complete the service we can for example inject an EJB and include the JAXB ObjectFactory.
And the contract first web service is finished.

Wednesday, August 10, 2011

Expose your Session Bean as a Web Service with JAX-WS and Eclipselink

In this blogpost I will show you how you can expose your EJB Session Bean as a Web Service, also tell you everything what I encountered and how I solved my issues. I will do this in JDeveloper and I will use the following frameworks: Eclipselink, JAX-WS and test it on WebLogic.

First let's start with the JPA part. In my project I generated some entities based on the Emp &amp;amp; Dept tables of the Scott schema.

In this demo I want to retrieve one department so I need to add a NamedQuery. I added Dept.findByPK to the NamedQueries annotation. Normally you only need to add the following JQL statement select o from Dept o where o.deptno = :deptid 
In this case I didn't want to set the OneToMany relation between Emp and Dept to eager. This can cause a fetch loop, so let's use the default value ( lazy ). I still need to fetch the employees on a department so I can return the department with all its employees in the Web Service response. To also fetch the employees I can add join fetch o.empList to the JQL statement.  



The Emp entity also got some important adjustments.
This entity got an attribute called hiredate with  timestamp as java type. First I added the Temporal annotation with a Date value and also change the java type to Calendar else it will be ignored by the Web Service.
Because this entity has a getter to the Dept entity and Dept got one to Emp we need to break the loop for the Web Service response. You can do this by adding the XmlTransient annotation to the getDept() method. Else you will get an empty response or this error
javax.xml.stream.XMLStreamException: Premature end of file encountered


This is my Session Bean where I added the WebService, WebMethod and WebParam annotation to the session bean to control the WSDL.

When you change one of these annotations you can get an deployment compiler error  like

weblogic.utils.AssertionError: ***** ASSERTION FAILED ***** Caused by: java.lang.ClassNotFoundException: nl.amis.model.services.ScottSessionBean_esxgzy_WSOImpl
at weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:297).

To fix this you need to remove the EJBCompilerCache folder located in MiddlewareJDevPS5\jdeveloper\system11.1.1.5.37.60.13\DefaultDomain\servers\DefaultServer\cache

Also in Eclipselink I used getResultList() and return a list instead of using GetSingleResult(). With GetSingleResult you get an error when there is no result. So you need to handle that when you use it.
At last we can also remove the Web Service annotations from the Session Bean, create a new class and maybe do Contract first . ( this will fix the EJBcompiler errors and keeps it more clean.) In this class I inject the Session Bean to a private variable and call it's ejb methods.
Now you can run it and test the EJB Web Service.