This section describes what you need to knw in order to change the look and feel of the Discovery Service. To control what is sent to the user interface you should consult DSUserInterface

The look and feel is controlled via a JSP file and an example wayf.jsp is provided with the standard distribution. This documentation draws on the contents and comments in that file.

Mode specific Beans

The DS can work in two modes. WAYF ("where are you from") or DS (Discovery Service) mode. Although much of the detail available to the jsp is the same in both cases there are a few beans which are specific to each. These beans are usually sent straight back to the DS when the GUI completes.

DS specific beans

These beans are as described in the Discovery Service Protocol.

WAYF specific beans.

The beans are the same as the parameters to the AuthnRequest message. They need to be returned as parameters of the same name. They are

Example jsp sequence to call back to the DS as part of a <form>
<logic:notPresent name="entityID" scope="request">
    <input type="hidden" name="shire" value="<bean:write name="shire" />" />
    <input type="hidden" name="target" value="<bean:write name="target" />" />
    <input type="hidden" name="providerId" value="<bean:write name="providerId" />" />
    <logic:present name="time" scope="request">
         <input type="hidden" name="time" value="<bean:write name="time" />" />
    </logic:present>
</logic:notPresent>
<logic:present name="entityID" scope="request">
    <input type="hidden" name="entityID" value="<bean:write name="entityID" />" />
    <input type="hidden" name="returnX" value="<bean:write name="returnX" />" />
   <input type="hidden" name="returnIDParam" value="<bean:write name="returnIDParam" />" />
</logic:present>

This code is taken from the example wayf.jsp which also has an example of contructing a URL to pass the request directly back to the SP or IdP (depending on the protocol)

Mode independant Beans

This is the information which the DS provides to the JSP.

Other parameters the JSP has to pass back to the DS

The jsp communicates back to the DS via the Mode specific parameters listed above, and:

Accessing the metadata extension for login and discovery

As a side-effect of updated the supporting libraries in the V1.1.3 release the DS can access the information described in <mdui:UIInfo> extensions, as described here

This is relatively complex and requires confidence with Java programming, JSP deployment and a reasonable working knowledge of the OpenSAML support for metadata.

The following describes some “recipes” for accessing this information in V1.1.3.

This information will change in later versions. We expect to have to make substantial alterations to support these changes.
These code segments are provided as is. Remember this is not a supported interface.

Importing the required libraries

The code segment below requires that certain packages are declared:

<%@ page language="java" import="java.util.*, edu.internet2.middleware.shibboleth.wayf.*, java.lang.*, org.opensaml.xml.*, org.opensaml.saml2.common.*, org.opensaml.saml2.metadata.*, org.opensaml.samlext.saml2mdui.*, javax.servlet.http.*, java.net.*"%>
Locating the MDUI information for the SP

In non-error cases, an object representing the SP is available via the attribute named “providerObject”. The code section below shows how to access the SP, and navigate to find the <mdui:DisplayName> and <mdui:Logo>. Note that no filtering for size or language is being applied.

Finally, if no name is located, the entity name is inspected to try to generate a “user friendly” display name for the SP.

<%
  String spName = null;
  String spLogo = null;
  EntityDescriptor sp = (EntityDescriptor) request.getAttribute("providerObject");
  if (null != sp) {
    List<RoleDescriptor> roles = sp.getRoleDescriptors();
    for (RoleDescriptor r:roles) {
      Extensions ex = r.getExtensions();
      if (null == ex) { 
        continue;
      }
      List<XMLObject> splist = ex.getOrderedChildren();
      for (XMLObject o:splist) { 
        if (o instanceof UIInfo) { 
          UIInfo info=null;
          info = (UIInfo) o;
          if (info.getLogos() != null) {
            for (Logo logo : info.getLogos()) { 
              if (logo.getHeight() <= 16 && logo.getWidth() <= 16) continue;
              if (null == spLogo) spLogo = logo.getURL();
              break;
            }
            for (DisplayName dn : info.getDisplayNames()) { 
              if (null == spName) spName = dn.getName().getLocalString();
              break;
            }
          }
        }
      }
    }
    if (spName == null) {
      try {
        URI uriId = new URI(sp.getEntityID());
        String scheme = uriId.getScheme();
  
        if ("http".equals(scheme) || "https".equals(scheme)) {
          spName = uriId.getHost(); 
        } else {
          spName = sp.getEntityID();
        }
      } catch (URISyntaxException e) {
        // 
        // It wasn't an URI.  return full entityId.
        //
        spName = sp.getEntityID();
      }
    }
  } else {
    spName = "Unknown Service Provider";
  }
%> 
Locating all available Logos for the IdPs

As described in the prototype wayf.jsp file the sites are available via the request attribute terms “sites”. The code segment below sets up a JavaScript associative array of icons (logos of size 16x16) and logos selected for best fit (according to the same rules that the Shibboleth EDS uses). Again language is ignored but could be trivially added.

<%
  double bestRatio = Math.log(80.0/60.0);
  sites = (TreeSet<IdPSite>) request.getAttribute("sites");
%>
<script type="text/javascript">
  var theIcons =[];
  var theLogos=[];
<%
  for (IdPSite site:sites) { 
     if (null == site.getExtensions()) { continue; }
     List<XMLObject> list = site.getExtensions().getOrderedChildren();
     UIInfo info=null;
     for (XMLObject o:list) { 
        if (o instanceof UIInfo) { 
          info = (UIInfo) o;
          break;
        }
     }
     if (info == null) { continue;}
     if (null == info.getLogos() || 0 == info.getLogos().size()) { continue;}
     String logoUrl = null;
     String iconUrl = null;
     double curRatio = 0;
     for (Logo logo : info.getLogos()) { 
        if (logo.getHeight() <= 16 && logo.getWidth() <= 16) {
	   iconUrl = logo.getURL();
           continue;
        }
        if (logoUrl == null) {
	   logoUrl = logo.getURL();
           curRatio = Math.log(logo.getWidth()/logo.getHeight());
           continue;
        }
        double ratio = Math.log(logo.getWidth()/logo.getHeight());
        double him = Math.abs(bestRatio - curRatio);
        double me = Math.abs(bestRatio - curRatio);
        if (him > me) {
	   logoUrl = logo.getURL();
           curRatio = ratio;
        }
     }
     if (logoUrl != null) {
       %> theLogos['<%=site.getName()%>']='<%=logoUrl%>'; <%
     }
     if (iconUrl != null) {
       %> theIcons['<%=site.getName()%>']='<%=iconUrl%>'; <%
     }
   }
%>
</script>
Accessing other information

This should be a relatively simple extension of the code samples above. Interested parties are encouraged to add to this code page.