View Javadoc

    1   /*
    2    * Copyright 2011 University Corporation for Advanced Internet Development, Inc.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    * http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package edu.internet2.middleware.shibboleth.idp.ui;
    18
    19  import java.net.URI;
    20  import java.net.URISyntaxException;
    21  import java.util.List;
    22
    23  import javax.servlet.ServletContext;
    24  import javax.servlet.http.HttpServletRequest;
    25  import javax.servlet.jsp.tagext.BodyTagSupport;
    26
    27  import org.opensaml.saml2.common.Extensions;
    28  import org.opensaml.saml2.metadata.AttributeConsumingService;
    29  import org.opensaml.saml2.metadata.EntityDescriptor;
    30  import org.opensaml.saml2.metadata.LocalizedString;
    31  import org.opensaml.saml2.metadata.RoleDescriptor;
    32  import org.opensaml.saml2.metadata.SPSSODescriptor;
    33  import org.opensaml.saml2.metadata.ServiceName;
    34  import org.opensaml.samlext.saml2mdui.DisplayName;
    35  import org.opensaml.samlext.saml2mdui.UIInfo;
    36  import org.opensaml.xml.XMLObject;
    37  import org.owasp.esapi.ESAPI;
    38  import org.owasp.esapi.Encoder;
    39  import org.slf4j.Logger;
    40  import org.slf4j.LoggerFactory;
    41
    42  import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfigurationManager;
    43  import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
    44  import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;
    45
    46
    47  /**
    48   * Display the serviceName.
    49   *
    50   * This is taken in order
    51   *  1) From the mdui
    52   *  2) AttributeConsumeService
    53   *  3) HostName from the EntityId
    54   *  4) EntityId.
    55   */
    56  public class ServiceTagSupport extends BodyTagSupport{
    57
    58      /**
    59       * checkstyle requires this serialization info.
    60       */
    61      private static final long serialVersionUID = 7988646597267865255L;
    62
    63      /** Class logger. */
    64      private static Logger log = LoggerFactory.getLogger(ServiceTagSupport.class);
    65
    66      /** Bean storage. class reference*/
    67      private String cssClass;
    68      /** Bean storage. id reference*/
    69      private String cssId;
    70      /** Bean storage. style reference*/
    71      private String cssStyle;
    72
    73      /** Bean setter.
    74       * @param value what to set
    75       */
    76      public void setCssClass(String value) {
    77          cssClass = value;
    78      }
    79      /** Bean setter.
    80       * @param value what to set
    81       */
    82      public void setCssId(String value) {
    83          cssId = value;
    84      }
    85
    86      /** Bean setter.
    87       * @param value what to set
    88       */
    89      public void setCssStyle(String value) {
    90          cssStyle = value;
    91      }
    92
    93      /**
    94       * Add the class and Id if present.
    95       * @param sb the stringbuilder to asdd to.
    96       */
    97      protected void addClassAndId(StringBuilder sb) {
    98          if (cssClass != null) {
    99              sb.append(" class=\"").append(cssClass).append('"');
    100         }
    101         if (cssId != null) {
    102             sb.append(" id=\"").append(cssId).append('"');
    103         }
    104         if (cssStyle != null) {
    105             sb.append(" style=\"").append(cssStyle).append('"');
    106         }
    107     }
    108
    109     /**
    110      * build a hyperlink from the parameters.
    111      * @param url the URL
    112      * @param text what to embed
    113      * @return the hyperlink.
    114      */
    115     protected String buildHyperLink(String url, String text) {
    116         String encodedUrl;
    117         Encoder esapiEncoder = ESAPI.encoder();
    118
    119         try {
    120             URI theUrl = new URI(url);
    121             String scheme = theUrl.getScheme();
    122
    123             if (!"http".equals(scheme) && !"https".equals(scheme) && !"mailto".equals(scheme)) {
    124                 log.warn("The URL " + url + " contained an invalid scheme");
    125                 return "";
    126             }
    127             encodedUrl = esapiEncoder.encodeForHTMLAttribute(url);
    128         } catch (URISyntaxException e) {
    129             //
    130             // It wasn't an URI.
    131             //
    132             log.warn("The URL " + url + " was invalid: " + e.toString());
    133             return "";
    134         }
    135
    136         StringBuilder sb = new StringBuilder("<a href=\"");
    137         sb.append(encodedUrl).append('"');
    138         addClassAndId(sb);
    139         sb.append(">").append(text).append("</a>");
    140         return sb.toString();
    141     }
    142
    143     /**
    144      * Get the EntityDescriptor for the relying party.
    145      * @return the SPs EntityDescriptor
    146      */
    147     protected EntityDescriptor getSPEntityDescriptor() {
    148         LoginContext loginContext;
    149         HttpServletRequest request;
    150         ServletContext application;
    151         RelyingPartyConfigurationManager rpConfigMngr;
    152         EntityDescriptor spEntity;
    153
    154         //
    155         // Populate up those things that jsp gives us.
    156         //
    157         request = (HttpServletRequest) pageContext.getRequest();
    158         application = pageContext.getServletContext();
    159
    160         if (request == null || application == null) {
    161            return null;
    162         }
    163         //
    164         // grab the login context and the RP config mgr.
    165         //
    166         loginContext = HttpServletHelper.getLoginContext(HttpServletHelper.getStorageService(application),
    167                 application, request);
    168         rpConfigMngr = HttpServletHelper.getRelyingPartyConfigurationManager(application);
    169         if (loginContext == null || rpConfigMngr == null) {
    170             return null;
    171         }
    172         spEntity = HttpServletHelper.getRelyingPartyMetadata(loginContext.getRelyingPartyId(), rpConfigMngr);
    173
    174         return spEntity;
    175     }
    176     /**
    177      * Traverse the SP's EntityDescriptor and pick out the UIInfo.
    178      * @return the first UIInfo for the SP.
    179      */
    180     protected UIInfo getSPUIInfo() {
    181         EntityDescriptor spEntity = getSPEntityDescriptor();
    182         Extensions exts;
    183
    184         if (null == spEntity) {
    185             //
    186             // all done
    187             //
    188             return null;
    189         }
    190
    191         for (RoleDescriptor role:spEntity.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME)) {
    192             exts = role.getExtensions();
    193             if (exts != null) {
    194                 for (XMLObject object:exts.getOrderedChildren()) {
    195                     if (object instanceof UIInfo) {
    196                         return (UIInfo) object;
    197                     }
    198                 }
    199             }
    200         }
    201         return null;
    202     }
    203
    204     /**
    205      * Pluck the language from the browser.
    206      * @return the two letter language
    207      */
    208     protected String getBrowserLanguage() {
    209         HttpServletRequest request;
    210         request = (HttpServletRequest) pageContext.getRequest();
    211
    212         return request.getLocale().getLanguage();
    213     }
    214     /**
    215      * If the entityId can look like a host return that otherwise the string.
    216      * @return either the host or the entityId.
    217      */
    218     private String getNameFromEntityId() {
    219         EntityDescriptor sp = getSPEntityDescriptor();
    220
    221         if (null == sp) {
    222             log.debug("No relying party, nothing to display");
    223             return null;
    224         }
    225
    226         try {
    227             URI entityId = new URI(sp.getEntityID());
    228             String scheme = entityId.getScheme();
    229
    230             if ("http".equals(scheme) || "https".equals(scheme)) {
    231                 return entityId.getHost();
    232             }
    233         } catch (URISyntaxException e) {
    234             //
    235             // It wasn't an URI.  return full entityId.
    236             //
    237             return sp.getEntityID();
    238         }
    239         //
    240         // not a URL return full entityID
    241         //
    242         return sp.getEntityID();
    243     }
    244
    245     /**
    246      * look at &lt;Uiinfo&gt; if there and if so look for appropriate name.
    247      * @return null or an appropriate name
    248      */
    249     private String getNameFromUIInfo() {
    250         String lang = getBrowserLanguage();
    251
    252         if (getSPUIInfo() != null) {
    253             for (DisplayName name:getSPUIInfo().getDisplayNames()) {
    254                 if (log.isDebugEnabled()){
    255                     log.debug("Found name in UIInfo, language=" + name.getXMLLang());
    256                 }
    257                 if (name.getXMLLang().equals(lang)) {
    258                     //
    259                     // Found it
    260                     //
    261                     if (log.isDebugEnabled()){
    262                         log.debug("returning name from UIInfo " + name.getName().getLocalString());
    263                     }
    264                     return name.getName().getLocalString();
    265                 }
    266             }
    267             if (log.isDebugEnabled()){
    268                 log.debug("No name in UIInfo");
    269             }
    270         }
    271         return null;
    272     }
    273
    274     /**
    275      * look for an &ltAttributeConsumeService&gt and if its there look for an appropriate name.
    276      * @return null or an appropriate name
    277      */
    278     private String getNameFromAttributeConsumingService(){
    279         String lang = getBrowserLanguage();
    280         List<RoleDescriptor> roles;
    281         AttributeConsumingService acs = null;
    282         EntityDescriptor sp = getSPEntityDescriptor();
    283
    284         if (null == sp) {
    285             log.warn("No relying party, nothing to display");
    286             return null;
    287         }
    288
    289         roles = sp.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
    290         if (!roles.isEmpty()) {
    291             SPSSODescriptor spssod = (SPSSODescriptor) roles.get(0);
    292             acs = spssod.getDefaultAttributeConsumingService();
    293         }
    294         if (acs != null) {
    295             for (ServiceName name:acs.getNames()) {
    296                 LocalizedString localName = name.getName();
    297                 if (log.isDebugEnabled()){
    298                     log.debug("Found name in AttributeConsumingService, language=" + localName.getLanguage());
    299                 }
    300                 if (localName.getLanguage().equals(lang)) {
    301                     if (log.isDebugEnabled()){
    302                         log.debug("returning name from AttributeConsumingService " + name.getName().getLocalString());
    303                     }
    304                     return localName.getLocalString();
    305                 }
    306             }
    307             if (log.isDebugEnabled()){
    308                 log.debug("No name in AttributeConsumingService");
    309             }
    310         }
    311         return null;
    312     }
    313
    314     /**
    315      * Get the identifier for the service name as per the rules above.
    316      * @return something sensible for display.
    317      */
    318     protected String getServiceName() {
    319         String result;
    320         //
    321         // First look for MDUI
    322         //
    323         if (getSPEntityDescriptor() == null) {
    324             log.debug("No relying party, nothing to display");
    325             return null;
    326         }
    327         //
    328         // Look at <UIInfo>
    329         //
    330         result = getNameFromUIInfo();
    331         if (result != null) {
    332             return result;
    333         }
    334
    335         //
    336         // Otherwise <AttributeConsumingService>
    337         //
    338         result = getNameFromAttributeConsumingService();
    339         if (result != null) {
    340             return result;
    341         }
    342
    343         //
    344         // Or look at the entityName
    345         //
    346         return getNameFromEntityId();
    347     }
    348
    349
    350 }