I have used Jetty as OpenIG container (version jetty-distribution-8.1.17.v20150415).
Install Jetty as a service
Download the Jetty distribution and unpack it in the traget directory. Follow instructions in http://www.eclipse.org/jetty/documentation/current/startup-windows-service.html
Several remarks:
- In the install.bat batch change the
set PR_JVMOPTIONS=
line toset PR_JVMOPTIONS=-Duser.dir="%JETTY_BASE%";-Djetty.port=8081;-Djava.io.tmpdir="C:\jetty\temp";-Djetty.home="%JETTY_HOME%";-Djetty.base="%JETTY_BASE%";-Dopenig.base="C:\jetty\OpenIG";-Xdebug;-Xnoagent;-Djava.compiler=NONE;-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005;
so that the used port will be 8081, the debug support will be enabled and the OpenIG base directory will be set up - Removing the service can be done with the command
prunsrv.exe //DS/JettyService4OpenIG
(JettyService4OpenIG is the chosen name for the service); - In order to be able to stop the service I had to remove comment the following lines in the install.bat:
REM set PR_STOPPARAMS=--stop;STOP.KEY="%STOPKEY%";STOP.PORT=%STOPPORT%;STOP.WAIT=10
REM --StartParams="%PR_STARTPARAMS%" ^
Deploy OpenIG
Rename the war to root.war
and deploy it to webapps; remove test.xml from contexts (so that the test application is not deployed (with error))
Deploy J2EE Agent
Follow the instructions in https://backstage.forgerock.com/#!/docs/openam-policy-agents/3.5.0/jee-users-guide#chap-jetty in parallel with https://backstage.forgerock.com/#!/docs/openig/3.1.0/gateway-guide#chap-password-capture-replay-tutorial to deploy the agent on the same Jetty instance
Configure the Agent
- Go to the newly defined realm (let's say it's named MyRealm) and select the Agents tab
- Select the J2EE tab
- Add a new Agent; be sure to use the port configured in Jetty (8081 in my case) in defining URLs:
- Set
Agent Filter Mode
toSSO_ONLY
- Set the
OpenAM Login URL
to contain therealm=MyRealm
query parameter* - Change the
webdefault.xml
in etc subdirectory of Jetty installation as mentioned in J2EE agent configuration (https://backstage.forgerock.com/#!/docs/openig/3.1.0/gateway-guide#capture-relay-setup-pa) but use<url-pattern>/replay/*</url-pattern>
instead of<url-pattern>/replay/</url-pattern>
(see below...).
- Set
Notices:
- Even if the agent is defined as part for MyRealm configuration and the property
com.sun.identity.agents.config.organization.name = /MyRealm
in agents bootstrap properties (OpenSSOAgentBootstrap.properties) is set up properly the generated login URL (at runtime) will not contain the targeted realm so user authentication will take place against Top Level Realm. - Password relay will not work with XUI interface due to a bug solved in subsequent 12.0.0 releases (available only to subscribers) so the solution is to switch to classic UI (https://bugster.forgerock.org/jira/browse/OPENAM-5921). See https://backstage.forgerock.com/#!/docs/openam/12.0.0/install-guide/chap-custom-ui on how to disable XUI.
- Changing /repaly to /replay/* will allow us to integrate more than one legacy applications in the system by using different specific routes in OpenIG; the ideea is that any GET to <OpenIG-URL>/relay/MyApp will trigger the same replay process by redirecting the user to OpenAM login dialog; the redirect back to OpenIG will be at the same URL which now will be forwarded to OpenIG which in turn based on this URL different routes can come into action (see OpenIG specifics below).
Configure OpenIG
There is not obvious at the first glance but we must define the config.js in config subdirectory of the configuread OpenIG base directory (parameter -Dopenig.base, see above) and the specific routes in config\routes.
config.js
{
"handler": {
"type": "Router",
"audit": "global",
"capture": "all"
},
"heap": [
{
"name": "LogSink",
"type": "ConsoleLogSink",
"config": {
"level": "DEBUG"
}
},
{
"name": "JwtSession",
"type": "JwtSession"
},
{
"name": "ClientHandler",
"type": "ClientHandler"
},
{
"name": "capture",
"type": "CaptureDecorator",
"config": {
"captureEntity": true,
"_captureExchange": true
}
}
]
}
Routes for OTRS
Login route
{
"handler": {
"type": "Chain",
"config": {
"filters": [
{
"type": "CryptoHeaderFilter",
"config": {
"messageType": "REQUEST",
"operation": "DECRYPT",
"algorithm": "DES/ECB/NoPadding",
"key": "xxx",
"keyType": "DES",
"charSet": "utf-8",
"headers": [
"password"
]
}
},
{
"type": "AssignmentFilter",
"config": {
"onRequest": [
{
"target": "${exchange.authInfoUsername}",
"value": "${exchange.request.headers['username'][0]}"
},
{
"target": "${exchange.authInfoPassword}",
"value": "${exchange.request.headers['password'][0]}"
}
]
}
},
{
"type": "HeaderFilter",
"config": {
"messageType": "REQUEST",
"remove": [
"password",
"username"
]
}
},
{
"type": "StaticRequestFilter",
"config": {
"method": "POST",
"uri": "https://otrs-fqdn/otrs/customer.pl",
"form": {
"User": [
"${exchange.authInfoUsername}"
],
"Password": [
"${exchange.authInfoPassword}"
],
"Action":["Login"],
"RequestedURL":[""],
"Lang":["en"],
"TimeOffset":["-180"]
}
}
}
],
"handler": "ClientHandler"
}
},
"condition": "${matches(exchange.request.uri.path, '^/replay/otrs')}"
}
Default route
{
"handler": "ClientHandler",
"condition": "${matches(exchange.request.uri.path, '^/otrs')}",
"baseURI": "https://otrs-fqdn"
}
Routes for othe application (two steps login)
This application is JSF based so the POST at login view must have the session cookie set. The solution is to have a first step requesting GET before so that the session is created.
Login route
{
"heap": [
{
"name": "DispatchHandler",
"type": "DispatchHandler",
"config": {
"bindings": [
{
"handler": {
"type": "Chain",
"config": {
"filters": [
{
"type": "CryptoHeaderFilter",
"config": {
"messageType": "REQUEST",
"operation": "DECRYPT",
"algorithm": "DES/ECB/NoPadding",
"key": "xxx",
"keyType": "DES",
"charSet": "utf-8",
"headers": [
"password"
]
}
},
{
"type": "AssignmentFilter",
"config": {
"onRequest": [
{
"target": "${exchange.authInfoUsername}",
"value": "${exchange.request.headers['username'][0]}"
},
{
"target": "${exchange.authInfoPassword}",
"value": "${exchange.request.headers['password'][0]}"
}
]
}
},
{
"type": "HeaderFilter",
"config": {
"messageType": "REQUEST",
"remove": [
"password",
"username"
]
}
},
{
"type": "StaticRequestFilter",
"config": {
"method": "GET",
"uri": "http://legacy-app-fqdn:8081/MyApp/faces/login.xhtml"
}
},
{
"type": "SwitchFilter",
"config": {
"onResponse": [
{
"handler": "LoginRequestHandler"
}
]
}
},
{
"type": "EntityExtractFilter",
"config": {
"messageType": "response",
"target": "${exchange.viewState}",
"bindings": [
{
"key": "value",
"pattern":
"javax\\.faces\\.ViewState\"\\s.*value=\"(.*)\"\\s*autocomplete=",
"template": "$1"
}
]
}
},
{
"type": "AssignmentFilter",
"config": {
"onResponse": [
{
"target": "${exchange.sessionCookie}",
"value": "${split(exchange.response.headers['Set-Cookie'][0],';')[0]}"
}
]
}
}
],
"handler": "ClientHandler"
}
}
}
]
}
},
{
"name": "LoginRequestHandler",
"type": "Chain",
"config": {
"filters": [
{
"type": "StaticRequestFilter",
"config": {
"method": "POST",
"uri": "http://legacy-app-fqdn:8081/MyApp/faces/login.xhtml",
"form": {
"loginForm:j_username": [
"${exchange.authInfoUsername}"
],
"loginForm:j_password": [
"${exchange.authInfoPassword}"
],
"loginForm":["loginForm"],
"loginForm:j_idt17":[""],
"javax.faces.ViewState":["${exchange.viewState.value}"]
},
"headers": {
"Cookie": ["${exchange.sessionCookie}"]
}
}
},
{
"type": "HeaderFilter",
"config": {
"messageType": "RESPONSE",
"add": {
"Set-Cookie": [ "${exchange.sessionCookie}; path=/MyApp" ]
}
}
}
],
"handler": "ClientHandler"
}
}
],
"handler": "DispatchHandler",
"condition": "${matches(exchange.request.uri.path, '^/replay/MyApp')}"
}
Default route
{
"handler": "ClientHandler",
"condition": "${matches(exchange.request.uri.path, '^/MyApp')}",
"baseURI": "http://legacy-app-fqdn:8081"
}
Several remarks
As I decided to abandon this solution there were things unconfigured or missconfigured. Just to mention two:
- Logout process (you might end up with the simulation of SSO screwed up if the users logout of one the application trying to re-log-in as a different user)
- Sniffing the network during tests I noticed announcement (POSTs if I remember corectly) from OpenAM to J2EE agent, messages not intercepted by the agent and forwarded (or dropped, depending on default router configuration) by OpenIG
Join the OpenAM saga as it strikes back! Unleash the power of seamless integration by diving into the installation and configuration of Jetty for the OpenIG-J2EE Agent. This guide is your lightsaber on the journey to mastering the force of OpenAM. May the configurations be with you! 💻🌌 #OpenAM #Jetty #TechJedi
ReplyDelete