View Javadoc

    1   /*
    2    * Copyright 2006 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.authn;
    18
    19  import java.io.Serializable;
    20  import java.io.StringWriter;
    21  import java.util.ArrayList;
    22  import java.util.List;
    23
    24  import org.opensaml.Configuration;
    25  import org.opensaml.saml2.core.AuthnContext;
    26  import org.opensaml.saml2.core.AuthnContextClassRef;
    27  import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration;
    28  import org.opensaml.saml2.core.AuthnContextDeclRef;
    29  import org.opensaml.saml2.core.AuthnRequest;
    30  import org.opensaml.saml2.core.RequestedAuthnContext;
    31  import org.opensaml.xml.io.Marshaller;
    32  import org.opensaml.xml.io.MarshallingException;
    33  import org.opensaml.xml.io.UnmarshallingException;
    34  import org.opensaml.xml.util.DatatypeHelper;
    35  import org.opensaml.xml.util.XMLHelper;
    36  import org.slf4j.Logger;
    37  import org.slf4j.LoggerFactory;
    38  import org.w3c.dom.Element;
    39
    40  /**
    41   * A SAML 2.0 {@link LoginContext}.
    42   *
    43   * This class can interpret {@link RequestedAuthnContext} and act accordingly.
    44   */
    45  public class Saml2LoginContext extends LoginContext implements Serializable {
    46
    47      /** Serial version UID. */
    48      private static final long serialVersionUID = -7117092606828289070L;
    49
    50      /** Relay state from authentication request. */
    51      private String relayState;
    52
    53      /** Serialized authentication request. */
    54      private String serialAuthnRequest;
    55
    56      /**
    57       * Creates a new instance of Saml2LoginContext.
    58       *
    59       * @param relyingParty entity ID of the relying party
    60       * @param state relay state from incoming authentication request
    61       * @param request SAML 2.0 Authentication Request
    62       *
    63       * @throws MarshallingException thrown if the given request can not be marshalled and serialized into a string
    64       */
    65      public Saml2LoginContext(String relyingParty, String state, AuthnRequest request) throws MarshallingException {
    66          super();
    67
    68          if (relyingParty == null || request == null) {
    69              throw new IllegalArgumentException("SAML 2 authentication request and relying party ID may not be null");
    70          }
    71          setRelyingParty(relyingParty);
    72          relayState = state;
    73          serialAuthnRequest = serializeRequest(request);
    74
    75          setForceAuthRequired(request.isForceAuthn());
    76          setPassiveAuthRequired(request.isPassive());
    77          getRequestedAuthenticationMethods().addAll(extractRequestedAuthenticationMethods(request));
    78      }
    79
    80      /**
    81       * Gets the serialized authentication request that started the login process.
    82       *
    83       * @return authentication request that started the login process
    84       *
    85       * @throws UnmarshallingException thrown if the serialized form on the authentication request can be unmarshalled
    86       */
    87      public synchronized String getAuthenticationRequest() throws UnmarshallingException {
    88          return serialAuthnRequest;
    89      }
    90
    91      /**
    92       * Gets the relay state from the originating authentication request.
    93       *
    94       * @return relay state from the originating authentication request
    95       */
    96      public synchronized String getRelayState(){
    97          return relayState;
    98      }
    99
    100     /**
    101      * Serializes an authentication request into a string.
    102      *
    103      * @param request the request to serialize
    104      *
    105      * @return the serialized form of the string
    106      *
    107      * @throws MarshallingException thrown if the request can not be marshalled and serialized
    108      */
    109     protected String serializeRequest(AuthnRequest request) throws MarshallingException {
    110         Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(request);
    111         Element requestElem = marshaller.marshall(request);
    112         StringWriter writer = new StringWriter();
    113         XMLHelper.writeNode(requestElem, writer);
    114         return writer.toString();
    115     }
    116
    117
    118     /**
    119      * Extracts the authentication methods requested within the request.
    120      *
    121      * @param request the authentication request
    122      *
    123      * @return requested authentication methods, or an empty list if no preference
    124      */
    125     protected List<String> extractRequestedAuthenticationMethods(AuthnRequest request){
    126         ArrayList<String> requestedMethods = new ArrayList<String>();
    127
    128         RequestedAuthnContext authnContext = request.getRequestedAuthnContext();
    129         if (authnContext == null) {
    130             return requestedMethods;
    131         }
    132
    133         // For the immediate future, we only support the "exact" comparator.
    134         AuthnContextComparisonTypeEnumeration comparator = authnContext.getComparison();
    135         if (comparator != null && comparator != AuthnContextComparisonTypeEnumeration.EXACT) {
    136             Logger log = LoggerFactory.getLogger(Saml2LoginContext.class);
    137             log.error("Unsupported comparision operator ( " + comparator
    138                     + ") in RequestedAuthnContext. Only exact comparisions are supported.");
    139             return requestedMethods;
    140         }
    141
    142         // build a list of all requested authn classes and declrefs
    143         List<AuthnContextClassRef> authnClasses = authnContext.getAuthnContextClassRefs();
    144         if (authnClasses != null) {
    145             for (AuthnContextClassRef classRef : authnClasses) {
    146                 if (classRef != null && !DatatypeHelper.isEmpty(classRef.getAuthnContextClassRef())) {
    147                     requestedMethods.add(classRef.getAuthnContextClassRef());
    148                 }
    149             }
    150         }
    151
    152         List<AuthnContextDeclRef> authnDeclRefs = authnContext.getAuthnContextDeclRefs();
    153         if (authnDeclRefs != null) {
    154             for (AuthnContextDeclRef declRef : authnDeclRefs) {
    155                 if (declRef != null&& !DatatypeHelper.isEmpty(declRef.getAuthnContextDeclRef())) {
    156                     requestedMethods.add(declRef.getAuthnContextDeclRef());
    157                 }
    158             }
    159         }
    160
    161         if(requestedMethods.contains(AuthnContext.UNSPECIFIED_AUTHN_CTX)){
    162             requestedMethods.clear();
    163         }
    164
    165         return requestedMethods;
    166     }
    167 }