Introduction
Enterprise Application Integration is a major order of the day, and making varied technology applications to talk between them is an uphill task. This article describes on how a .NET based application could talk to a j2EE based application run on WebLogic behind a security wall posed by �Webseal�. The major tasks identified to have a seamless working application developed with a j2EE based application run on Weblogic and a .NET application are:
- Maintenance of session between j2EE based application and .NET application.
- Maintenance of security framework as existing in j2EE based application.
- Exchange of data without any binding on data types.
- Exchange of data without much restriction on protocol layers and ports.
Background
Framework at Web Server application:
VB.NET Windows client application exchanges data and user interface with j2EE based web application developed in STRUTS framework, with the application server as Weblogic 7.0. All the resources (Java class files) deployed in app server have to be accessed via Sun One Portal with �Webseal� as its security feature.
Approach to Solution:
- Session Maintenance:
Weblogic servers maintain their session with a unique identifier jsessionid
. Every HTTP request from the client is identified with this jsessionid
for tracking the session with client. This session tracking is done in two aspects, either:
- As a cookie sent from the browser
or
- As URL rewriting by appending the
jsessionid
as a query string in each request
- Security Maintenance:
The security feature implemented in this case along with Weblogic and Sun One portal is �Webseal�. Webseal authorizes each of the resources it allows to access by generating a webseal identifier after successful login, and sending it as a cookie (PD-H-SESSION-ID) for tracking the subsequent requests. If the cookie is not identified properly in the subsequent request for the session, access to resources is denied by �Web Seal�.
Cookies Values: |
Cookie Name |
Value |
Remarks |
PD-H-SESSION-ID |
Randomly generated for each session |
Generated by WebSeal |
Cookie Name |
Randomly generated for each session |
Generated by WebLogic |
- Exchange of data:
Since the .NET application accessing web resources may come behind a firewall, it was decided to make all the requests as HTTP requests. The output response from web server will be either a HTML page for user interface, or an XML document over HTTP which will be parsed at the VB.NET application end to process the data.
Solution:
The .NET application is a Windows based application developed in VB.NET. IE control and System.web.HTTPUtility
namespace are used for accessing the j2EE based web application.
IE control is used for making a HTTP request to j2EE based web application and displaying it in browser window if needed.
System.web.HTTPUtility
is used for making HTTP request and getting the required data in an XML format as a response stream from j2EE based web application.
Using the code
A new IE process is initiated to have the control of browser window targeted at Login screen of the application.
Friend libSWs As SHDocVw.ShellWindows
Friend libDoc As mshtml.HTMLDocument
Friend WithEvents libIE As SHDocVw.InternetExplorer
Friend objIE As New Object
Private Function InitiateIE ()
Try
Dim strIEExecutablePath As String = ""
StrIEExecutablePath = GetBrowserName ()
If Trim (strIEExecutablePath) <> "" Then
libSWs = New SHDocVw.ShellWindows
A new process is created for control of removing all resources when the browser window is closed. This is needed because, IE control otherwise holds the resource since it associates with existing IExplore.exe process if any browser window is already open.
prcStartInfo = New ProcessStartInfo (strIEExecutablePath,<LOGIN URL>)
prcStartInfo.WindowStyle = ProcessWindowStyle.Minimized
prcStartInfo.UseShellExecute = True
SetStatusText(DOWNLOADING_IN_PROGRESS)
prcInitprocess = New Process
prcInitprocess.StartInfo = prcStartInfo
prcInitprocess.Start()
prcInitprocess.WaitForInputIdle ()
pWHnd = prcInitprocess.MainWindowHandle
hWndIe = pWHnd.ToInt64
For Each objIE In libSWs
If TypeName(objIE) = "IWebBrowser2" Then
libIE = objIE
If hWndIe = libIE.HWND Then
libIE.AddressBar = False
libIE.MenuBar = False
libIE.ToolBar = False
libIE.Visible = True
SetWindowFront (hWndIe)
While libIE.ReadyState <> READYSTATE_COMPLETE
End While
If libIE.ReadyState = READYSTATE_COMPLETE Then
libDoc = libIE.Document
SetStatusText(DOWNLOADING_COMPLETED)
blnSessionflg = False
blnIsLoginEnabled = True
blnTimerEnabled = True
End If
End If
End If
Next
End If
Catch exp As Exception
MessageBox.Show(exp.ToString)
End Try
End Function
Login credentials are filled and submitted for authentication. Webseal authenticates valid users and sends a security cookie () along with the home page/initial page of the application. In the download event of home page/initial page of the application in the browser, the security cookie is read from document cookie and stored for further requests through System.Web.httputility
. In the following code snippet, Weblogic session (jsessionid
) is also tracked, since after login, home page from Weblogic is accessed, thus creating a new session.
'//Code snippet
'
'This function is called in the download event of the
'browser window. It retrieves the webseal and weblogic
'cookie values for appending it in subsequent requests
'for maintaining the session values...
Public Function TrackSession()
Try
For Each objIE in libSWs
If TypeName(objIE) = "IWebBrowser2" Then
'if this is an HTML page, navigate.
libIE = objIE
'Checking whether same window handle
If hWndIe = libIE.HWND Then
libIE.AddressBar = False
libIE.MenuBar = False
libIE.ToolBar = False
libIE.Visible = True
'See if the weblogic session has been created and track the
'cookie information required for authentication...
'setting the document object
libDoc = libIE.Document
Dim title As String
'Capture the browser instance that has this title
'and use the same for future calls.
title = "MY title"
If libDoc.title = title Then
'Get the cookie val.
strCookieVal = libDoc.cookie
'SetNetCookieCollection(strCookieVal)
str_g_cookieval = strCookieVal
'Parse and assign the cookie val....
ParseCookie(strCookieVal)
'set the session value as on
blnSessionflg = True
Exit For
End If
End If
End If
Next
Catch exp as Exception
End Try
End Function
Private Function ParseCookie (ByVal strCookie As String) As String
'Assigns webseal and jession identifier values...
Dim arrCookieVal() As String
Dim strWebLogicCookie As String
Dim arrWebLogicCookie() As String
Dim strWebSealCookie As String
Dim arrWebSealCookie() As String
Dim intCounter As Integer
arrCookieVal = strCookie.Split(";")
For intCounter = 0 To arrCookieVal.Length - 1
If InStr(arrCookieVal(intCounter), "SESSION_IDS_OF_ADAPTER") Then
strWebLogicCookie = arrCookieVal(intCounter)
arrWebLogicCookie = strWebLogicCookie.Split("#")
JSESSION_ID = JSESSION_ID & arrWebLogicCookie(1)
strMethodUrl = strMethodUrl & JSESSION_ID
ElseIf InStr(arrCookieVal(intCounter), "PD-H-SESSION-ID") Then
strWebSealCookie = arrCookieVal(intCounter)
arrWebSealCookie = strWebSealCookie.Split("=")
WEB_SEALCOOKIE_NM = arrWebSealCookie(0)
WEB_SEALCOOKIE_VAL = arrWebSealCookie(1)
End If
Next
End Function
Once the security and session cookies are obtained in the VB.NET application, j2EE based application could be accessed as below:
- Through initiated browser window as normal web application, by appending
jessionid
in URL.
A JSESSIONID
cookie value is appended to the URL as a query string parameter.
Example: http://www.yyyy.com/UI123?JSESSIONID=xxxxx.
- Through
System.web.httputility
for getting XML data over HTTP response.
Webseal session cookie value (PD-H-SESSION-ID) is set initially on the requesting URL, and method call request is made appending JSESSIONID
cookie value to the URL as a query string parameter.
Example: http://www.yyyy.com/MC123?JSESSIONID=xxxxx.
NavigateToUrl(http://www.yyyy.com/UI123?JSESSIONID=xxxxx.)
Public Function NavigateToUrl(ByVal strUrl As String, _
ByVal blnAsync As Object, ByVal trgFrame As Object, _
ByVal objPostData As Object, ByVal objHeader As Object)
Try
For Each objIE In libSWs
If TypeName(objIE) = "InternetExplorerClass" _
Or TypeName(objIE) = "IWebBrowser2" Then
libIE = objIE
If hWndIe = libIE.HWND Then
libIE.AddressBar = False
libIE.MenuBar = False
libIE.ToolBar = False
libIE.Visible = True
libIE.Navigate(strUrl, blnAsync, _
trgFrame, objPostData, objHeader)
While libIE.ReadyState <> READYSTATE_COMPLETE
Application.DoEvents()
End While
Exit For
End If
End If
Next
Catch exp As Exception
Messagebox(exp.ToString)
End Try
End Function
Accessing web application through System.web.httputility
Source code snippet for making method calls (XML over HTTP).
This class is representing the same functionality of xmlHTTP
object in MSXML.XMLHTTP
.
Imports System.Net
Imports System.Web.HttpUtility
Function main ()
StrMethdoURL ="http://www.yyy.com/ IntegrationServlet;" & _
" jsessionid=AhFj18NaW5AEe1o0EvNH1u1gw8P3Yjq" & _
"1TMNUyWiSI1t2ce0TJL9Y!567889692! 1075906019681"
PostData = "TargetName=GetPreOrders&FromDate=&ToDate=&ReferenceNo=1"
response = ProcessData(strMethdoURL,PostData)
End Function
Public Function ProcessData(ByVal strUrl As String, _
ByVal postdata As String) As String
Dim xmlHTTP As New XMLHTTP
Dim strXML As String
xmlHTTP.open("POST", strUrl)
xmlHTTP.Send(postdata)
strXML = xmlHTTP.ResponseText()
DisplayXML(ParseXML(strXML))
ProcessData = strXML
End Function
Public Class XMLHTTP
Public Overridable Sub open(ByVal bstrMethod As String, _
ByVal bstrUrl As String, Optional ByVal varAsync As _
Object = False, Optional ByVal bstrUser _
As Object = "", Optional ByVal bstrPassword As Object = "")
Try
strUrl = bstrUrl
strMethod = bstrMethod
If blnIsProxy Then
proxyObject = WebProxy.GetDefaultProxy()
If Not (IsNothing(proxyObject.Address)) Then
uriAddress = proxyObject.Address
If Not (IsNothing(uriAddress)) Then
_ProxyName = uriAddress.Host
_ProxyPort = uriAddress.Port
End If
UpdateProxy()
End If
urlWebRequest.Proxy = proxyObject
End If
urlWebRequest = System.Net.HttpWebRequest.Create(strUrl)
urlWebRequest.Method = strMethod
If (strMethod = "POST") Then
setRequestHeader("Content-Type", _
"application/x-www-form-urlencoded")
End If
urlWebRequest.Headers.Add("Cookie", str_g_cookieval)
Catch exp As Exception
SetErrStatusText("Error opening method level url connection")
End Try
End Sub
Public Overridable Sub Send(Optional ByVal objBody As Object = "")
Try
Dim rspResult As System.Net.HttpWebResponse
Dim strmRequestStream As System.IO.Stream
Dim strmReceiveStream As System.IO.Stream
Dim encode As System.Text.Encoding
Dim sr As System.IO.StreamReader
Dim bytBytes() As Byte
Dim UrlEncoded As New System.Text.StringBuilder
Dim reserved() As Char = {ChrW(63), ChrW(61), ChrW(38)}
urlWebRequest.Expect = Nothing
If (strMethod = "POST") Then
If objBody <> Nothing Then
Dim intICounter As Integer = 0
Dim intJCounter As Integer = 0
While intICounter < objBody.Length
intJCounter = _
objBody.IndexOfAny(reserved, intICounter)
If intJCounter = -1 Then
UrlEncoded.Append(System.Web.HttpUtility.UrlEncode(objBody.Substring(intICounter, _
objBody.Length - intICounter)))
Exit While
End If
UrlEncoded.Append(System.Web.HttpUtility.UrlEncode(objBody.Substring(intICounter, _
intJCounter - intICounter)))
UrlEncoded.Append(objBody.Substring(intJCounter, 1))
intICounter = intJCounter + 1
End While
bytBytes = _
System.Text.Encoding.UTF8.GetBytes(UrlEncoded.ToString())
urlWebRequest.ContentLength = bytBytes.Length
strmRequestStream = urlWebRequest.GetRequestStream
strmRequestStream.Write(bytBytes, 0, bytBytes.Length)
strmRequestStream.Close()
Else
urlWebRequest.ContentLength = 0
End If
End If
rspResult = urlWebRequest.GetResponse()
strmReceiveStream = rspResult.GetResponseStream()
encode = System.Text.Encoding.GetEncoding("utf-8")
sr = New System.IO.StreamReader(strmReceiveStream, encode)
Dim read(256) As Char
Dim count As Integer = sr.Read(read, 0, 256)
Do While count > 0
Dim str As String = New String(read, 0, count)
strResponseText = strResponseText & str
count = sr.Read(read, 0, 256)
Loop
Catch exp As Exception
SetErrStatusText("Error while sending parameters")
WritetoLog(exp.ToString)
End Try
End Sub
Public Overridable Sub setRequestHeader(ByVal bstrHeader _
As String, ByVal bstrValue As String)
Select Case bstrHeader
Case "Referer"
urlWebRequest.Referer = bstrValue
Case "User-Agent"
urlWebRequest.UserAgent = bstrValue
Case "Content-Type"
urlWebRequest.ContentType = bstrValue
Case Else
urlWebRequest.Headers(bstrHeader) = bstrValue
End Select
End Sub
Private Function UpdateProxy()
Try
If Not (IsNothing(uriAddress)) Then
If ((Not IsNothing(_ProxyName)) And _
(_ProxyName.Length > 0) And (_ProxyPort > 0)) Then
proxyObject = New WebProxy(_ProxyName, _ProxyPort)
Dim strByPass() As String = Split(strByPassList, "|")
If strByPass.Length > 0 Then
proxyObject.BypassList = strByPass
End If
proxyObject.BypassProxyOnLocal = True
If blnNetworkCredentials Then
If strDomain <> "" Then
proxyObject.Credentials = New _
NetworkCredential(strUserName, _
strPwd, strDomain)
Else
proxyObject.Credentials = New _
NetworkCredential(strUserName, _
strPwd)
End If
End If
End If
End If
Catch exp As Exception
SetErrStatusText("Error while updating proxy configurations")
WritetoLog(exp.ToString)
End Try
End Function
Public Overridable ReadOnly Property ResponseText() As String
Get
ResponseText = strResponseText
End Get
End Property
Private urlWebRequest As System.Net.HttpWebRequest
Private urlWebResponse As System.Net.HttpWebResponse
Private strResponseText As String
Private strUrl As String
Private strMethod As String
Private proxyObject As WebProxy
Private intCount As Integer
Private uriAddress As Uri
Private _ProxyName As String
Private _ProxyPort As Integer
End Class
Points of Interest
The data integrity between the two applications is maintained by defining an XML schema of the data exchanged through XML over HTTP which could be also a webservice. If the access to j2EE is through secured protocol layer, System.Security.Cryptography.X509Certificates
namespace could be used and HTTPS request could be authorized through.
System.Net.ServicePointManager.CertificatePolicy = New CertificatePolicy
The above could also be followed for ASP.NET applications to interact with j2EE based applications or any web services that could be accessed with port 8080 or 443.
History
This is the initial version. All comments are welcome.