Tuesday Jun 24, 2008
The Fedlet and U (Part 3): We Built This Application
NOTE : I've been getting errors with the following procedures. I am posting them anyway in hopes that someone can see what I have missed. I'm not an engineer and therefore am thinking my code deletion and additions are incorrect. If you are able to successfully deploy and test the following Fedlet procedures, let me know what you did so I can try it out. Thanks.
Thus far, in previous entries, I explained how to implement the Fedlet using the Common Tasks work flow in the OpenSSO console and using the pre-built but unconfiguredfedlet.war. (There's also a bonus entry on how to remove a deployed fedlet.)
In this entry, you'll find the procedures to integrate the fedlet.war code with an existing service provider application. The following diagram illustrates the three ways in which this can be done.
fedletSampleApp.jspis modified to add the service provider's application logic and, thus, is used as the endpoint for the Fedlet on the service provider side here.fedletSampleApp.jspis modified to forward the request to the service provider application URL and, thus, is also used as the endpoint for the Fedlet on the service provider side here.fedletSampleApp.jspis replaced by a new JSP (servlet) to create a new endpoint or the Fedlet code in thefedletSampleApp.jspis copied to the new endpoint code here.
fedletSampleApp.jsp, a sample JSP packaged with the fedlet.war thatprovides a default Assertion Consumer endpoint to process SAMLv2 Assertions from the identity provider. fedletSampleApp.jsp first invokes a util method to complete SAMLv2 protocol processing. A map containing various pieces of data (including a Response, an Assertion, and Attributes) is then returned to the caller for further processing. fedletSampleApp.jsp also provides some sample code to help you to understand how to retrieve data from the returned map.
<%--
The contents of this file are subject to the terms
of the Common Development and Distribution License
(the License). You may not use this file except in
compliance with the License.
You can obtain a copy of the License at
https://opensso.dev.java.net/public/CDDLv1.0.html or
opensso/legal/CDDLv1.0.txt
See the License for the specific language governing
permission and limitations under the License.
When distributing Covered Code, include this CDDL
Header Notice in each file and include the License file
at opensso/legal/CDDLv1.0.txt.
If applicable, add the following below the CDDL Header,
with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
$Id: fedletSampleApp.jsp,v 1.2 2008/05/29 00:40:42 veiming Exp $
Copyright 2008 Sun Microsystems Inc. All Rights Reserved
--%>
<%@page
import="com.sun.identity.saml2.common.SAML2Exception,
com.sun.identity.saml2.common.SAML2Constants,
com.sun.identity.saml2.assertion.Assertion,
com.sun.identity.saml2.assertion.Subject,
com.sun.identity.saml2.profile.SPACSUtils,
com.sun.identity.saml2.protocol.Response,
com.sun.identity.saml2.assertion.NameID,
com.sun.identity.plugin.session.SessionException,
java.io.IOException,
java.util.Iterator,
java.util.List,
java.util.Map"
%>
<%
String deployuri = request.getRequestURI();
int slashLoc = deployuri.indexOf("/", 1);
if (slashLoc != -1) {
deployuri = deployuri.substring(0, slashLoc);
}
%>
<html>
<head>
<title>Fedlet Sample Application</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="<%= deployuri %>/com_sun_web_ui/css/css_ns6up.css" />
</head>
<body>
<div class="MstDiv"><table width="100%" border="0" cellpadding="0" cellspacing="0" class="MstTblTop" title="">
<tbody><tr>
<td nowrap="nowrap"> </td>
<td nowrap="nowrap"> </td>
</tr></tbody></table>
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="MstTblBot" title="">
<tbody><tr>
<td class="MstTdTtl" width="99%">
<div class="MstDivTtl"><img name="ProdName" src="<%= deployuri %>/console/images/PrimaryProductName.png" alt="" /></div></td><td class="MstTdLogo" width="1%"><img name="RMRealm.mhCommon.BrandLogo" src="<%= deployuri %>/com_sun_web_ui/images/other/javalogo.gif" alt="Java(TM) Logo" border="0" height="55" width="31" /></td></tr></tbody></table>
<table class="MstTblEnd" border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img name="RMRealm.mhCommon.EndorserLogo" src="<%= deployuri %>/com_sun_web_ui/images/masthead/masthead-sunname.gif" alt="Sun(TM) Microsystems,
Inc." align="right" border="0" height="10" width="108" /></td></tr></tbody></table></div><div class="SkpMedGry1"><a name="SkipAnchor2089" id="SkipAnchor2089"></a></div>
<div class="SkpMedGry1"><a href="#SkipAnchor4928"><img src="<%= deployuri %>/com_sun_web_ui/images/other/dot.gif" alt="Jump Over Tab Navigation Area. Current Selection is: Access Control" border="0" height="1" width="1" /></a></div>
<%
// BEGIN : following code is a must for Fedlet (SP) side application
Map map;
try {
// invoke the Fedlet processing logic. this will do all the
// necessary processing conforming to SAMLv2 specifications,
// such as XML signature validation, Audience and Recipient
// validation etc.
map = SPACSUtils.processResponseForFedlet(request, response);
} catch (SAML2Exception sme) {
response.sendError(response.SC_INTERNAL_SERVER_ERROR, sme.getMessage());
return;
} catch (IOException ioe) {
response.sendError(response.SC_INTERNAL_SERVER_ERROR, ioe.getMessage());
return;
} catch (SessionException se) {
response.sendError(response.SC_INTERNAL_SERVER_ERROR, se.getMessage());
return;
} catch (ServletException se) {
response.sendError(response.SC_BAD_REQUEST, se.getMessage());
return;
}
// END : code is a must for Fedlet (SP) side application
String relayUrl = (String) map.get(SAML2Constants.RELAY_STATE);
if ((relayUrl != null) && (relayUrl.length() != 0)) {
// something special for validation to send redirect
int stringPos = relayUrl.indexOf("sendRedirectForValidationNow=true");
if (stringPos != -1) {
response.sendRedirect(relayUrl);
}
}
// Following are sample code to show how to retrieve information,
// such as Reponse/Assertion/Attributes, from the returned map.
// You might not need them in your real application code.
Response samlResp = (Response) map.get(SAML2Constants.RESPONSE);
Assertion assertion = (Assertion) map.get(SAML2Constants.ASSERTION);
Subject subject = (Subject) map.get(SAML2Constants.SUBJECT);
String entityID = (String) map.get(SAML2Constants.IDPENTITYID);
NameID nameId = assertion.getSubject().getNameID();
String value = nameId.getValue();
String format = nameId.getFormat();
out.println("<br><br><b>Single Sign-On successful with IDP "
+ entityID + ".</b>");
out.println("<br><br>");
out.println("<table border=0>");
if (format != null) {
out.println("<tr>");
out.println("<td valign=top><b>Name ID format: </b></td>");
out.println("<td>" + format + "</td>");
out.println("</tr>");
}
if (value != null) {
out.println("<tr>");
out.println("<td valign=top><b>Name ID value: </b></td>");
out.println("<td>" + value + "</td>");
out.println("</tr>");
}
Map attrs = (Map) map.get(SAML2Constants.ATTRIBUTE_MAP);
if (attrs != null) {
out.println("<tr>");
out.println("<td valign=top><b>Attributes: </b></td>");
Iterator iter = attrs.keySet().iterator();
out.println("<td>");
while (iter.hasNext()) {
String attrName = (String) iter.next();
List attrVals = (List) attrs.get(attrName);
out.println(attrName + "="
+ attrVals.get(0) + "<br>");
}
out.println("</td>");
out.println("</tr>");
}
out.println("</table>");
out.println("<br><br><b><a href=# onclick=toggleDisp('resinfo')>Click to view SAML2 Response XML</a></b><br>");
out.println("<span style='display:none;' id=resinfo><textarea rows=40 cols=100>" + samlResp.toXMLString(true, true) + "</textarea></span>");
out.println("<br><b><a href=# onclick=toggleDisp('assr')>Click to view Assertion XML
<script>
function toggleDisp(id)
{
var elem = document.getElementById(id);
if (elem.style.display == 'none')
elem.style.display = '';
else
elem.style.display = 'none';
}
</script>
</body>
</html>
The following procedures assume that you have downloaded the opensso.zip and extracted the contents. The
/opensso directory is at the top-level of the machine to which it was downloaded.
Modify fedletSampleApp.jsp with Application Logic
- Unzip
fedlet.warinto a temporal directory; for example,/sp1.
This directory must be accessible by the user running the web container; for example, if running your web container as root, the user's home directory is/so thesp1directory should be located at/sp1. NOTE: This directory is the default location from which the Fedlet reads its metadata, circle of trust, and configuration properties. To change it, set the value of the JVM run-time propertycom.sun.identity.fedlet.hometo the desired location; for example:-Dcom.sun.identity.fedlet.home=/export/fedlet/conf% mkdir /sp1 % cd /sp1 % jar xvf /opensso/fedlet/fedlet.war - In
fedletSampleApp.jsp(located at the top-level of the temporal directory) remove all text after the line,// END : code is a must for Fedlet (SP) side application. - Merge the import statements between
fedletSampleApp.jspand the application code, if applicable.
I'm using a simplehello.jsp(as below) so nothing to merge.
<%-- The contents of this file are subject to the terms of the Common Development and Distribution License (the License). You may not use this file except in compliance with the License. You can obtain a copy of the License at https://opensso.dev.java.net/public/CDDLv1.0.html or opensso/legal/CDDLv1.0.txt See the License for the specific language governing permission and limitations under the License. When distributing Covered Code, include this CDDL Header Notice in each file and include the License file at opensso/legal/CDDLv1.0.txt. If applicable, add the following below the CDDL Header, with the fields enclosed by brackets [] replaced by your own identifying information: "Portions Copyrighted [year] [name of copyright owner]" $Id: fedletDefault.jsp,v 1.2 2008/03/31 19:54:11 qcheng Exp $ Copyright 2008 Sun Microsystems Inc. All Rights Reserved --%> <html> <head> <title>My Hello</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <h1> Hello World </h1> </body> </html> - Add your application logic underneath the line that begins with
//END- prepending a%>before it and appending the closing HTML tags after it.&> <h1> Hello, World </h1> </body> </html> - From inside the
sp1directory, pack up the contents using thejarcommand.
jar cvf ./fedlet.war - Deploy the WAR.
- Launch the deployed application.
fedletSampleApp.jsp to Forward Request
- Unzip
fedlet.warinto a temporal directory; for example,sp2.
% mkdir sp2 % cd sp2 % jar xvf /opensso/fedlet/fedlet.war - In
fedletSampleApp.jsp(located at the top-level of the temporal directory) remove all text after the line,// END : code is a must for Fedlet (SP) side application. - Add redirect code underneath the line that begins with
//END- prepending a%>before it and appending the closing HTML tags after it.&> response.sendRedirect("hello.jsp"); </body> </html> - Add the modified
fedletSampleApp.jspand thehello.jspto the document root of the unpacked WAR directory structure. - Pack up the WAR using the
jarcommand.
jar cvf ./fedlet.war - Deploy the WAR.
- Launch the deployed application.
fedletSampleApp.jsp
- Modify
web.xmlto set the servlet and servlet-mapping for your new servlet or JSP.
You must map your new servlet/JSP to the url-pattern/fedletapplicationsince that is the URI set in the Fedlet metadata for the assertion consumer URL. For example:yourapplication /Your-Application.jsp yourapplication /fedletapplication - Copy the following code from
fedletSampleApp.jspto your application processing code.
Be sure to also copy any appropriate import statements.
After obtaining the returnedMap map; try { // invoke the Fedlet processing logic. this will do all the Map map; try { // invoke the Fedlet processing logic. this will do all the // necessary processing conforming to SAMLv2 specifications, // such as XML signature validation, Audience and Recipient // validation etc. map = SPACSUtils.processResponseForFedlet(request, response); } catch (SAML2Exception sme) { response.sendError(response.SC_INTERNAL_SERVER_ERROR, sme.getMessage()); return; } catch (IOException ioe) { response.sendError(response.SC_INTERNAL_SERVER_ERROR, ioe.getMessage()); return; } catch (SessionException se) { response.sendError(response.SC_INTERNAL_SERVER_ERROR, se.getMessage()); return; } catch (ServletException se) { response.sendError(response.SC_BAD_REQUEST, se.getMessage()); return; }mapobject, follow the sample code to retrieve the data needed for your business logics.
Posted at 07:55AM Jun 24, 2008 by Michael Teger in Sun | Comments[4]

I was wondering what errors you were getting. I'm running the fedSampleApp.jsp which does some similar stuff. I'm blowing up at map = SPACSUtils.processResponseForFedlet(request, response);
I was wondering if you are blowing up at the some place.
Posted by Mike Sacauskis on March 30, 2009 at 04:32 PM PDT #
Mike, I can't remember what my errors were. I suggest you send your error info to users@opensso.dev.java.net. There's a lot of people on that alias who will be able to help.
Posted by DocTeger on March 30, 2009 at 04:41 PM PDT #
Hi,
I didn't try your tutorial for now but please forgive me if I'm wrong :
I was looking at the Fedlet generating menu and maybe when we create it we should declare <SP Host URL>/<our application> in the SP end-point field instead of <SP Host URL>/"fedlet".
i think these declarations are written in the metadatas in the IDP side, and it could not match the right SP for the federation after we modify the fedlet's configuration files.
Posted by lourderadj on October 08, 2009 at 05:45 AM PDT #
Hi. Maybe that's why I could never get this to work. Or maybe the metadata has changed since I wrote this entry. Why don't you check it out and let us know if it worked for you? ;>
Posted by Michael Teger on October 08, 2009 at 08:29 AM PDT #