Rev POM up to 2.3.3-SNAPSHOT
authorrdw <rdw@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 31 Aug 2011 13:32:40 +0000 (13:32 +0000)
committerrdw <rdw@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 31 Aug 2011 13:32:40 +0000 (13:32 +0000)
https://issues.shibboleth.net/jira/browse/SIDP-514 Alt text for IdP Logos is not esapiEncoder.encodeForHTMLAttribute
https://issues.shibboleth.net/jira/browse/SIDP-513 idpui taglib could look for more languages matches

git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/branches/REL_2@3065 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

doc/RELEASE-NOTES.txt
pom.xml
src/main/java/edu/internet2/middleware/shibboleth/idp/ui/ServiceDescriptionTag.java
src/main/java/edu/internet2/middleware/shibboleth/idp/ui/ServiceInformationURLTag.java
src/main/java/edu/internet2/middleware/shibboleth/idp/ui/ServiceLogoTag.java
src/main/java/edu/internet2/middleware/shibboleth/idp/ui/ServicePrivacyURLTag.java
src/main/java/edu/internet2/middleware/shibboleth/idp/ui/ServiceTagSupport.java

index 95f4635..00fb89e 100644 (file)
@@ -1,3 +1,8 @@
+Changes in Release 2.3.4
+=============================================
+[SIDP-513] idpui taglib could look for more languages matches
+[SIDP-514] Alt text for IdP Logos is not esapiEncoder.encodeForHTMLAttribute
+
 Changes in Release 2.3.3
 =============================================
 [SIDP-504] - Alt text generate for logo has mismatched quoting
diff --git a/pom.xml b/pom.xml
index ee80a85..cfe42bf 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
 
     <groupId>edu.internet2.middleware</groupId>
     <artifactId>shibboleth-identityprovider</artifactId>
-    <version>2.3.3</version>
+    <version>2.3.4-SNAPSHOT</version>
 
     <!-- We bundle as a jar here, the installer creates the WAR -->
     <packaging>jar</packaging>
index 90c7aed..d202b3b 100644 (file)
@@ -41,51 +41,54 @@ import org.slf4j.LoggerFactory;
  * 
  */
 public class ServiceDescriptionTag extends ServiceTagSupport {
-    
+
     /** required by checkstyle. */
     private static final long serialVersionUID = -2000941439055969537L;
+
     /** Class logger. */
     private static Logger log = LoggerFactory.getLogger(ServiceDescriptionTag.class);
 
-    /** 
+    /**
      * look at &lt;Uiinfo&gt; if there and if so look for appropriate description.
+     * 
+     * @param lang - which language to look up
      * @return null or an appropriate description
      */
-    private String getDescriptionFromUIInfo() {
-        String lang = getBrowserLanguage();
-
+    private String getDescriptionFromUIInfo(String lang) {
         if (getSPUIInfo() != null && getSPUIInfo().getDescriptions() != null) {
-            for (Description desc:getSPUIInfo().getDescriptions()) {
-                if (log.isDebugEnabled()){
+
+            for (Description desc : getSPUIInfo().getDescriptions()) {
+                if (log.isDebugEnabled()) {
                     log.debug("Found description in UIInfo, language=" + desc.getXMLLang());
                 }
                 if (desc.getXMLLang().equals(lang)) {
                     //
                     // Found it
                     //
-                    if (log.isDebugEnabled()){
+                    if (log.isDebugEnabled()) {
                         log.debug("returning description from UIInfo " + desc.getName().getLocalString());
                     }
                     return desc.getName().getLocalString();
                 }
             }
-            if (log.isDebugEnabled()){
+            if (log.isDebugEnabled()) {
                 log.debug("No valid description in UIInfo");
-            }            
+            }
         }
         return null;
     }
-    
+
     /**
      * look for an &ltAttributeConsumeService&gt and if its there look for an appropriate description.
+     * 
+     * @param lang - which language to look up
      * @return null or an appropriate description
      */
-    private String getDescriptionFromAttributeConsumingService() {
-        String lang = getBrowserLanguage();
+    private String getDescriptionFromAttributeConsumingService(String lang) {
         List<RoleDescriptor> roles;
         AttributeConsumingService acs = null;
         EntityDescriptor sp = getSPEntityDescriptor();
-        
+
         if (null == sp) {
             log.debug("No relying party, nothing to display");
             return null;
@@ -97,48 +100,59 @@ public class ServiceDescriptionTag extends ServiceTagSupport {
             acs = spssod.getDefaultAttributeConsumingService();
         }
         if (acs != null) {
-            for (ServiceDescription desc:acs.getDescriptions()) {
+            for (ServiceDescription desc : acs.getDescriptions()) {
                 LocalizedString localDescription = desc.getDescription();
-                if (log.isDebugEnabled()){
+                if (log.isDebugEnabled()) {
                     log.debug("Found name in AttributeConsumingService, language=" + localDescription.getLanguage());
                 }
                 if (localDescription.getLanguage().equals(lang)) {
-                    if (log.isDebugEnabled()){
-                        log.debug("returning name from AttributeConsumingService " + 
-                                desc.getDescription().getLocalString());
+                    if (log.isDebugEnabled()) {
+                        log.debug("returning name from AttributeConsumingService "
+                                + desc.getDescription().getLocalString());
                     }
                     return localDescription.getLocalString();
                 }
             }
-            if (log.isDebugEnabled()){
+            if (log.isDebugEnabled()) {
                 log.debug("No description in AttributeConsumingService");
-            }            
-        }        
+            }
+        }
         return null;
     }
 
     @Override
     public int doEndTag() throws JspException {
-       
+
         Encoder esapiEncoder = ESAPI.encoder();
-        String result;
+        String result = null;
+
         //
-        // UIInfoirst
+        // For all languages
         //
-        result = getDescriptionFromUIInfo();
-        
-        if (result == null) {
+        for (String lang : getBrowserLanguages()) {
+
+            //
+            // UIInfoirst
+            //
+            result = getDescriptionFromUIInfo(lang);
+            if (null != result) {
+                break;
+            }
+
             //
             // Then AttributeCOnsumingService
             //
-            result = getDescriptionFromAttributeConsumingService();
+            result = getDescriptionFromAttributeConsumingService(lang);
+            if (null != result) {
+                break;
+            }
         }
 
         try {
             if (null == result) {
                 BodyContent bc = getBodyContent();
                 if (null != bc) {
-                    JspWriter ew= bc.getEnclosingWriter();
+                    JspWriter ew = bc.getEnclosingWriter();
                     if (ew != null) {
                         bc.writeOut(ew);
                     }
index e4367a8..49aea88 100644 (file)
@@ -27,63 +27,68 @@ import org.opensaml.samlext.saml2mdui.InformationURL;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**Service InformationURL - directly from the metadata if present.*/
+/** Service InformationURL - directly from the metadata if present. */
 public class ServiceInformationURLTag extends ServiceTagSupport {
-    
-    /** check style requires the serialVersionUID.*/
+
+    /** check style requires the serialVersionUID. */
     private static final long serialVersionUID = 5601822745575892676L;
+
     /** Class logger. */
     private static Logger log = LoggerFactory.getLogger(ServiceInformationURLTag.class);
 
     /** Bean storage for the link text attribute. */
     private static String linkText;
 
-    /** Bean setter  for the link text attribute.
+    /**
+     * Bean setter for the link text attribute.
+     * 
      * @param text the link text to put in
      */
     public void setLinkText(String text) {
         linkText = text;
     }
-    
+
     /**
      * look for the &lt;InformationURL&gt; in the &lt;UIInfo&gt;.
+     * 
      * @return null or an appropriate string.
      */
     private String getInformationURLFromUIIinfo() {
-        String lang = getBrowserLanguage();
-
         if (getSPUIInfo() != null && getSPUIInfo().getInformationURLs() != null) {
-            for (InformationURL infoURL:getSPUIInfo().getInformationURLs()) {
-                if (log.isDebugEnabled()){
-                    log.debug("Found InformationURL in UIInfo, language=" + infoURL.getXMLLang());
-                }
-                if (infoURL.getXMLLang().equals(lang)) {
-                    //
-                    // Found it
-                    //
-                    if (log.isDebugEnabled()){
-                        log.debug("returning URL from UIInfo " + infoURL.getURI().getLocalString());
+            for (String lang : getBrowserLanguages()) {
+
+                for (InformationURL infoURL : getSPUIInfo().getInformationURLs()) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Found InformationURL in UIInfo, language=" + infoURL.getXMLLang());
+                    }
+                    if (infoURL.getXMLLang().equals(lang)) {
+                        //
+                        // Found it
+                        //
+                        if (log.isDebugEnabled()) {
+                            log.debug("returning URL from UIInfo " + infoURL.getURI().getLocalString());
+                        }
+                        return infoURL.getURI().getLocalString();
                     }
-                    return infoURL.getURI().getLocalString();
                 }
             }
-            if (log.isDebugEnabled()){
+            if (log.isDebugEnabled()) {
                 log.debug("No relevant InformationURL in UIInfo");
-            }                       
+            }
         }
         return null;
     }
-    @Override
 
+    @Override
     public int doEndTag() throws JspException {
-       
+
         String infoURL = getInformationURLFromUIIinfo();
-        
+
         try {
             if (null == infoURL) {
                 BodyContent bc = getBodyContent();
                 if (null != bc) {
-                    JspWriter ew= bc.getEnclosingWriter();
+                    JspWriter ew = bc.getEnclosingWriter();
                     if (ew != null) {
                         bc.writeOut(ew);
                     }
@@ -98,5 +103,4 @@ public class ServiceInformationURLTag extends ServiceTagSupport {
         return super.doEndTag();
     }
 
-
 }
index cb59261..47dccc3 100644 (file)
@@ -20,6 +20,7 @@ package edu.internet2.middleware.shibboleth.idp.ui;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.List;
 
 import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.JspWriter;
@@ -31,57 +32,77 @@ import org.owasp.esapi.Encoder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**Logo for the SP.*/
+/** Logo for the SP. */
 public class ServiceLogoTag extends ServiceTagSupport {
 
     /**
      * checkstyle control.
      */
     private static final long serialVersionUID = 6451849117572923712L;
+
     /** Class logger. */
     private static Logger log = LoggerFactory.getLogger(ServiceLogoTag.class);
+
     /** what to emit if the jsp has nothing. */
     private static final String DEFAULT_VALUE = "";
+
     /** what to emit as alt txt if all else fails. */
     private static final String DEFAULT_ALT_TXT = "SP Logo";
 
     /** Bean storage. Size constraint X */
     private int minWidth;
+
     /** Bean storage. Size constraint X */
     private int maxWidth = Integer.MAX_VALUE;
+
     /** Bean storage. Size constraint Y */
     private int minHeight;
-    /** Bean storage.  Size constraint Y */
+
+    /** Bean storage. Size constraint Y */
     private int maxHeight = Integer.MAX_VALUE;
-    /** Bean storage.  alt text */
+
+    /** Bean storage. alt text */
     private String altTxt;
 
-    /** Bean setter.
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setMaxWidth(Integer value) {
         maxWidth = value.intValue();
     }
-    /** Bean setter.
+
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setMinWidth(Integer value) {
         minWidth = value.intValue();
     }
-    /** Bean setter.
+
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setMinHeight(Integer value) {
         minHeight = value.intValue();
     }
-    /** Bean setter.
+
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setMaxHeight(Integer value) {
         maxHeight = value.intValue();
     }
 
-    /** Bean setter.
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setAlt(String value) {
@@ -90,58 +111,75 @@ public class ServiceLogoTag extends ServiceTagSupport {
 
     /**
      * Whether the provided logo fits inside the constraints.
+     * 
      * @param logo the logo
      * @return whether it fits the provided max and mins
      */
     private boolean logoFits(Logo logo) {
-        return logo.getHeight() <= maxHeight && logo.getHeight() >= minHeight &&
-               logo.getWidth() <= maxWidth && logo.getWidth() >= minWidth;
+        return logo.getHeight() <= maxHeight && logo.getHeight() >= minHeight && logo.getWidth() <= maxWidth
+                && logo.getWidth() >= minWidth;
     }
     
     /**
-     * get an appropriate Logo from UIInfo.
-     * @return the URL for a logo
+     * get an appropriate logo by lanaguage from the UIInfo.
+     * @param logos what to look through
+     * @return an appropriate logo.
      */
-    private String getLogoFromUIInfo() {
-        String lang = getBrowserLanguage();
-
-        if (getSPUIInfo() != null && getSPUIInfo().getDescriptions() != null) {
-            for (Logo logo:getSPUIInfo().getLogos()) {
-                if (log.isDebugEnabled()){
-                    log.debug("Found logo in UIInfo, language=" + logo.getXMLLang() + 
-                            " width=" + logo.getWidth() + " height=" +logo.getHeight());
-                }
-                if (null != logo.getXMLLang() && !logo.getXMLLang().equals(lang)) {
-                    //
-                    // there is a language and its now what we want
+    private String getLogoFromUIInfo(List<Logo> logos) {
+        for (String lang : getBrowserLanguages()) {
+            // By language first
+            for (Logo logo : logos) {
+                log.debug("Found logo in UIInfo, language=" + logo.getXMLLang() + " width=" + logo.getWidth()
+                        + " height=" + logo.getHeight());
+                if (null == logo.getXMLLang() || !logo.getXMLLang().equals(lang) || !logoFits(logo)) {
+                    // No language, language mismatch or not fitting
                     continue;
                 }
-                if (!logoFits(logo)) {
-                    //
-                    // size out of range
-                    //
-                    continue;
-                }
-                //
                 // Found it
-                //
-                if (log.isDebugEnabled()) {
-                    log.debug("returning logo from UIInfo " + logo.getURL());
-                }
+                log.debug("returning logo from UIInfo " + logo.getURL());
+                return logo.getURL();
+            }
+        }
+        // Then by no language
+        for (Logo logo : getSPUIInfo().getLogos()) {
+            log.debug("Found logo in UIInfo, language=" + logo.getXMLLang() + " width=" + logo.getWidth()
+                    + " height=" + logo.getHeight());
+            if (null == logo.getXMLLang() && logoFits(logo)) {
+                // null language and it fits
+                log.debug("returning logo from UIInfo " + logo.getURL());
                 return logo.getURL();
             }
-            if (log.isDebugEnabled()){
-                log.debug("No appropriate logo in UIInfo");
-            }            
         }
         return null;
     }
-    
-    /** Find what the user specified for alt txt.
+
+    /**
+     * get an appropriate Logo from UIInfo.
+     * 
+     * @return the URL for a logo
+     * 
+     */
+    private String getLogoFromUIInfo() {
+
+        if (getSPUIInfo() != null && getSPUIInfo().getLogos() != null) {
+            
+            String result = getLogoFromUIInfo(getSPUIInfo().getLogos());
+            
+            if (null != result) {
+                return result;
+            }
+            log.debug("No appropriate logo in UIInfo");
+        }
+        return null;
+    }
+
+    /**
+     * Find what the user specified for alt txt.
+     * 
      * @return the text required
      */
     private String getAltText() {
-        
+
         //
         // First see what the user tried
         //
@@ -149,7 +187,7 @@ public class ServiceLogoTag extends ServiceTagSupport {
         if (null != value && 0 != value.length()) {
             return value;
         }
-        
+
         //
         // Try the request
         //
@@ -157,28 +195,28 @@ public class ServiceLogoTag extends ServiceTagSupport {
         if (null != value && 0 != value.length()) {
             return value;
         }
-        
+
         return DEFAULT_ALT_TXT;
     }
 
     /**
      * Given the url build an appropriate &lta href=...
+     * 
      * @return the contrcuted hyperlink or null
      */
     private String getHyperlink() {
         String url = getLogoFromUIInfo();
-        String encodedURL;
         StringBuilder sb;
         Encoder esapiEncoder = ESAPI.encoder();
-        
+
         if (null == url) {
             return null;
         }
-        
+
         try {
             URI theUrl = new URI(url);
             String scheme = theUrl.getScheme();
-    
+
             if (!"http".equals(scheme) && !"https".equals(scheme) && !"mailto".equals(scheme)) {
                 log.warn("The logo URL " + url + " contained an invalid scheme");
                 return null;
@@ -190,29 +228,29 @@ public class ServiceLogoTag extends ServiceTagSupport {
             log.warn("The logo URL " + url + " was not a URL " + e.toString());
             return null;
         }
-        
-        
-        encodedURL = esapiEncoder.encodeForHTMLAttribute(url);
+
+        String encodedURL = esapiEncoder.encodeForHTMLAttribute(url);
+        String encodedAltTxt = esapiEncoder.encodeForHTMLAttribute(getAltText());
 
         sb = new StringBuilder("<img src=\"");
         sb.append(encodedURL).append('"');
-        sb.append(" alt=\"").append(getAltText()).append('"');
+        sb.append(" alt=\"").append(encodedAltTxt).append('"');
         addClassAndId(sb);
         sb.append("/>");
         return sb.toString();
     }
-    
+
     @Override
     public int doEndTag() throws JspException {
-       
+
         String result = getHyperlink();
-        
+
         try {
             if (null == result) {
                 BodyContent bc = getBodyContent();
                 boolean written = false;
                 if (null != bc) {
-                    JspWriter ew= bc.getEnclosingWriter();
+                    JspWriter ew = bc.getEnclosingWriter();
                     if (ew != null) {
                         bc.writeOut(ew);
                         written = true;
index 0efe0bf..bdf00b8 100644 (file)
@@ -18,6 +18,7 @@
 package edu.internet2.middleware.shibboleth.idp.ui;
 
 import java.io.IOException;
+import java.util.List;
 
 import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.JspWriter;
@@ -27,65 +28,70 @@ import org.opensaml.samlext.saml2mdui.PrivacyStatementURL;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** Service PrivacyURL - directly from the metadata if present.*/
+/** Service PrivacyURL - directly from the metadata if present. */
 public class ServicePrivacyURLTag extends ServiceTagSupport {
 
     /** checkstyle needs serial version UID. */
     private static final long serialVersionUID = 1706444251504545781L;
-    
+
     /** Class logger. */
     private static Logger log = LoggerFactory.getLogger(ServicePrivacyURLTag.class);
 
     /** Bean storage for the link text attribute. */
     private static String linkText;
-    
-    /** Bean setter  for the link text attribute.
+
+    /**
+     * Bean setter for the link text attribute.
+     * 
      * @param text the link text to put in
      */
     public void setLinkText(String text) {
         linkText = text;
     }
-    
+
     /**
      * look for the &lt;PrivacyURL&gt; in the &lt;UIInfo&gt;.
+     * 
      * @return null or an appropriate string.
      */
     private String getPrivacyURLFromUIIinfo() {
-        String lang = getBrowserLanguage();
-
         if (getSPUIInfo() != null && getSPUIInfo().getPrivacyStatementURLs() != null) {
-            for (PrivacyStatementURL privacyURL:getSPUIInfo().getPrivacyStatementURLs()) {
-                if (log.isDebugEnabled()){
-                    log.debug("Found PrivacyStatementURL in UIInfo, language=" + privacyURL.getXMLLang());
-                }
-                if (privacyURL.getXMLLang().equals(lang)) {
-                    //
-                    // Found it
-                    //
-                    if (log.isDebugEnabled()){
-                        log.debug("returning URL from UIInfo " + privacyURL.getURI().getLocalString());
+            
+            List<String> languages = getBrowserLanguages();
+            for (String lang : languages) {
+
+                for (PrivacyStatementURL privacyURL : getSPUIInfo().getPrivacyStatementURLs()) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Found PrivacyStatementURL in UIInfo, language=" + privacyURL.getXMLLang());
+                    }
+                    if (privacyURL.getXMLLang().equals(lang)) {
+                        //
+                        // Found it
+                        //
+                        if (log.isDebugEnabled()) {
+                            log.debug("returning URL from UIInfo " + privacyURL.getURI().getLocalString());
+                        }
+                        return privacyURL.getURI().getLocalString();
                     }
-                    return privacyURL.getURI().getLocalString();
                 }
             }
-            if (log.isDebugEnabled()){
+            if (log.isDebugEnabled()) {
                 log.debug("No relevant PrivacyStatementURL in UIInfo");
-            }                       
+            }
         }
         return null;
     }
-    
-    @Override
 
+    @Override
     public int doEndTag() throws JspException {
-       
+
         String privacyURL = getPrivacyURLFromUIIinfo();
-        
+
         try {
             if (null == privacyURL) {
                 BodyContent bc = getBodyContent();
                 if (null != bc) {
-                    JspWriter ew= bc.getEnclosingWriter();
+                    JspWriter ew = bc.getEnclosingWriter();
                     if (ew != null) {
                         bc.writeOut(ew);
                     }
index ddac31f..e763ebb 100644 (file)
@@ -19,7 +19,10 @@ package edu.internet2.middleware.shibboleth.idp.ui;
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
+import java.util.Locale;
 
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
@@ -44,47 +47,51 @@ import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfi
 import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
 import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
 
-
 /**
  * Display the serviceName.
  * 
- * This is taken in order
- *  1) From the mdui
- *  2) AttributeConsumeService
- *  3) HostName from the EntityId
- *  4) EntityId.
+ * This is taken in order 1) From the mdui 2) AttributeConsumeService 3) HostName from the EntityId 4) EntityId.
  */
-public class ServiceTagSupport extends BodyTagSupport{
+public class ServiceTagSupport extends BodyTagSupport {
 
     /**
      * checkstyle requires this serialization info.
      */
     private static final long serialVersionUID = 7988646597267865255L;
-    
+
     /** Class logger. */
     private static Logger log = LoggerFactory.getLogger(ServiceTagSupport.class);
 
-    /** Bean storage. class reference*/
+    /** Bean storage. class reference */
     private String cssClass;
-    /** Bean storage. id reference*/
+
+    /** Bean storage. id reference */
     private String cssId;
-    /** Bean storage. style reference*/
+
+    /** Bean storage. style reference */
     private String cssStyle;
 
-    /** Bean setter.
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setCssClass(String value) {
         cssClass = value;
     }
-    /** Bean setter.
+
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setCssId(String value) {
         cssId = value;
     }
 
-    /** Bean setter.
+    /**
+     * Bean setter.
+     * 
      * @param value what to set
      */
     public void setCssStyle(String value) {
@@ -93,6 +100,7 @@ public class ServiceTagSupport extends BodyTagSupport{
 
     /**
      * Add the class and Id if present.
+     * 
      * @param sb the stringbuilder to asdd to.
      */
     protected void addClassAndId(StringBuilder sb) {
@@ -106,9 +114,10 @@ public class ServiceTagSupport extends BodyTagSupport{
             sb.append(" style=\"").append(cssStyle).append('"');
         }
     }
-    
+
     /**
      * build a hyperlink from the parameters.
+     * 
      * @param url the URL
      * @param text what to embed
      * @return the hyperlink.
@@ -116,7 +125,7 @@ public class ServiceTagSupport extends BodyTagSupport{
     protected String buildHyperLink(String url, String text) {
         String encodedUrl;
         Encoder esapiEncoder = ESAPI.encoder();
-       
+
         try {
             URI theUrl = new URI(url);
             String scheme = theUrl.getScheme();
@@ -127,22 +136,23 @@ public class ServiceTagSupport extends BodyTagSupport{
             }
             encodedUrl = esapiEncoder.encodeForHTMLAttribute(url);
         } catch (URISyntaxException e) {
-            // 
+            //
             // It wasn't an URI.
             //
             log.warn("The URL " + url + " was invalid: " + e.toString());
             return "";
         }
-        
+
         StringBuilder sb = new StringBuilder("<a href=\"");
         sb.append(encodedUrl).append('"');
         addClassAndId(sb);
-        sb.append(">").append(text).append("</a>");
+        sb.append(">").append(esapiEncoder.encodeForHTML(text)).append("</a>");
         return sb.toString();
     }
-    
+
     /**
      * Get the EntityDescriptor for the relying party.
+     * 
      * @return the SPs EntityDescriptor
      */
     protected EntityDescriptor getSPEntityDescriptor() {
@@ -151,21 +161,22 @@ public class ServiceTagSupport extends BodyTagSupport{
         ServletContext application;
         RelyingPartyConfigurationManager rpConfigMngr;
         EntityDescriptor spEntity;
-        
+
         //
         // Populate up those things that jsp gives us.
         //
         request = (HttpServletRequest) pageContext.getRequest();
         application = pageContext.getServletContext();
-        
+
         if (request == null || application == null) {
-           return null;
+            return null;
         }
         //
         // grab the login context and the RP config mgr.
         //
-        loginContext = HttpServletHelper.getLoginContext(HttpServletHelper.getStorageService(application),
-                application, request);
+        loginContext =
+                HttpServletHelper.getLoginContext(HttpServletHelper.getStorageService(application), application,
+                        request);
         rpConfigMngr = HttpServletHelper.getRelyingPartyConfigurationManager(application);
         if (loginContext == null || rpConfigMngr == null) {
             return null;
@@ -174,14 +185,16 @@ public class ServiceTagSupport extends BodyTagSupport{
 
         return spEntity;
     }
+
     /**
      * Traverse the SP's EntityDescriptor and pick out the UIInfo.
+     * 
      * @return the first UIInfo for the SP.
      */
     protected UIInfo getSPUIInfo() {
         EntityDescriptor spEntity = getSPEntityDescriptor();
         Extensions exts;
-        
+
         if (null == spEntity) {
             //
             // all done
@@ -189,10 +202,10 @@ public class ServiceTagSupport extends BodyTagSupport{
             return null;
         }
 
-        for (RoleDescriptor role:spEntity.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME)) {
+        for (RoleDescriptor role : spEntity.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME)) {
             exts = role.getExtensions();
             if (exts != null) {
-                for (XMLObject object:exts.getOrderedChildren()) {
+                for (XMLObject object : exts.getOrderedChildren()) {
                     if (object instanceof UIInfo) {
                         return (UIInfo) object;
                     }
@@ -201,24 +214,35 @@ public class ServiceTagSupport extends BodyTagSupport{
         }
         return null;
     }
-            
+
     /**
      * Pluck the language from the browser.
+     * 
      * @return the two letter language
      */
-    protected String getBrowserLanguage() {
+    protected List<String> getBrowserLanguages() {
         HttpServletRequest request;
         request = (HttpServletRequest) pageContext.getRequest();
-        
-        return request.getLocale().getLanguage();
+
+        Enumeration<Locale> locales = request.getLocales();
+
+        List<String> languages = new ArrayList<String>();
+
+        while (locales.hasMoreElements()) {
+            Locale locale = locales.nextElement();
+            languages.add(locale.getLanguage());
+        }
+        return languages;
     }
+
     /**
      * If the entityId can look like a host return that otherwise the string.
+     * 
      * @return either the host or the entityId.
      */
     private String getNameFromEntityId() {
         EntityDescriptor sp = getSPEntityDescriptor();
-        
+
         if (null == sp) {
             log.debug("No relying party, nothing to display");
             return null;
@@ -229,11 +253,11 @@ public class ServiceTagSupport extends BodyTagSupport{
             String scheme = entityId.getScheme();
 
             if ("http".equals(scheme) || "https".equals(scheme)) {
-                return entityId.getHost(); 
+                return entityId.getHost();
             }
         } catch (URISyntaxException e) {
-            // 
-            // It wasn't an URI.  return full entityId.
+            //
+            // It wasn't an URI. return full entityId.
             //
             return sp.getEntityID();
         }
@@ -242,82 +266,81 @@ public class ServiceTagSupport extends BodyTagSupport{
         //
         return sp.getEntityID();
     }
-    
-    /** 
+
+    /**
      * look at &lt;Uiinfo&gt; if there and if so look for appropriate name.
+     * 
+     * @param lang - which language to look up
      * @return null or an appropriate name
      */
-    private String getNameFromUIInfo() {
-        String lang = getBrowserLanguage();
+    private String getNameFromUIInfo(String lang) {
 
         if (getSPUIInfo() != null) {
-            for (DisplayName name:getSPUIInfo().getDisplayNames()) {
-                if (log.isDebugEnabled()){
+            for (DisplayName name : getSPUIInfo().getDisplayNames()) {
+                if (log.isDebugEnabled()) {
                     log.debug("Found name in UIInfo, language=" + name.getXMLLang());
                 }
                 if (name.getXMLLang().equals(lang)) {
                     //
                     // Found it
                     //
-                    if (log.isDebugEnabled()){
+                    if (log.isDebugEnabled()) {
                         log.debug("returning name from UIInfo " + name.getName().getLocalString());
                     }
                     return name.getName().getLocalString();
                 }
             }
-            if (log.isDebugEnabled()){
-                log.debug("No name in UIInfo");
-            }            
+            if (log.isDebugEnabled()) {
+                log.debug("No name in MDUI for " + lang);
+            }
         }
         return null;
     }
 
     /**
      * look for an &ltAttributeConsumeService&gt and if its there look for an appropriate name.
+     * 
+     * @param lang - which language to look up
      * @return null or an appropriate name
      */
-    private String getNameFromAttributeConsumingService(){
-        String lang = getBrowserLanguage();
-        List<RoleDescriptor> roles;
-        AttributeConsumingService acs = null;
+    private String getNameFromAttributeConsumingService(String lang) {
         EntityDescriptor sp = getSPEntityDescriptor();
-        
         if (null == sp) {
             log.warn("No relying party, nothing to display");
             return null;
         }
 
-        roles = sp.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+        AttributeConsumingService acs = null;
+
+        List<RoleDescriptor> roles = sp.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
         if (!roles.isEmpty()) {
             SPSSODescriptor spssod = (SPSSODescriptor) roles.get(0);
             acs = spssod.getDefaultAttributeConsumingService();
         }
         if (acs != null) {
-            for (ServiceName name:acs.getNames()) {
+            for (ServiceName name : acs.getNames()) {
                 LocalizedString localName = name.getName();
-                if (log.isDebugEnabled()){
+                if (log.isDebugEnabled()) {
                     log.debug("Found name in AttributeConsumingService, language=" + localName.getLanguage());
                 }
                 if (localName.getLanguage().equals(lang)) {
-                    if (log.isDebugEnabled()){
+                    if (log.isDebugEnabled()) {
                         log.debug("returning name from AttributeConsumingService " + name.getName().getLocalString());
                     }
                     return localName.getLocalString();
                 }
             }
-            if (log.isDebugEnabled()){
-                log.debug("No name in AttributeConsumingService");
-            }            
-        }        
+        }
         return null;
     }
-    
+
     /**
      * Get the identifier for the service name as per the rules above.
+     * 
      * @return something sensible for display.
      */
     protected String getServiceName() {
-        String result;
+        String result = null;
         //
         // First look for MDUI
         //
@@ -325,27 +348,32 @@ public class ServiceTagSupport extends BodyTagSupport{
             log.debug("No relying party, nothing to display");
             return null;
         }
-        //
-        // Look at <UIInfo>
-        //
-        result = getNameFromUIInfo();
-        if (result != null) {
-            return result;
-        }
         
         //
-        // Otherwise <AttributeConsumingService>
+        // For each Language
         //
-        result = getNameFromAttributeConsumingService();
-        if (result != null) {
-            return result;
+        List<String> languages = getBrowserLanguages();
+        for (String lang : languages) {
+            //
+            // Look at <UIInfo>
+            //
+            result = getNameFromUIInfo(lang);
+            if (result != null) {
+                return result;
+            }
+
+            //
+            // Otherwise <AttributeConsumingService>
+            //
+            result = getNameFromAttributeConsumingService(lang);
+            if (result != null) {
+                return result;
+            }
         }
-        
         //
         // Or look at the entityName
         //
         return getNameFromEntityId();
     }
-    
 
 }