View Javadoc

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