Package org.jboss.seam.security.external.saml.sp

Source Code of org.jboss.seam.security.external.saml.sp.SamlSpSingleSignOnService

package org.jboss.seam.security.external.saml.sp;

import java.util.LinkedList;
import java.util.List;

import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConstants;

import org.jboss.logging.Logger;
import org.jboss.seam.security.external.InvalidRequestException;
import org.jboss.seam.security.external.ResponseHandler;
import org.jboss.seam.security.external.SamlNameIdImpl;
import org.jboss.seam.security.external.SamlPrincipalImpl;
import org.jboss.seam.security.external.dialogues.DialogueBean;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AssertionType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AttributeStatementType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AttributeType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.AuthnStatementType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.NameIDType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.StatementAbstractType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.SubjectConfirmationDataType;
import org.jboss.seam.security.external.jaxb.samlv2.assertion.SubjectConfirmationType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.AuthnRequestType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.ResponseType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.StatusResponseType;
import org.jboss.seam.security.external.jaxb.samlv2.protocol.StatusType;
import org.jboss.seam.security.external.saml.SamlConstants;
import org.jboss.seam.security.external.saml.SamlDialogue;
import org.jboss.seam.security.external.saml.SamlEntityBean;
import org.jboss.seam.security.external.saml.SamlMessageFactory;
import org.jboss.seam.security.external.saml.SamlMessageSender;
import org.jboss.seam.security.external.saml.SamlProfile;
import org.jboss.seam.security.external.saml.SamlRedirectMessage;
import org.jboss.seam.security.external.saml.SamlServiceType;
import org.jboss.seam.security.external.saml.SamlUtils;
import org.jboss.seam.security.external.spi.SamlServiceProviderSpi;

/**
* @author Marcel Kolsteren
*
*/
@SuppressWarnings("restriction")
public class SamlSpSingleSignOnService
{
   @Inject
   private Logger log;

   @Inject
   private SamlSpSessions samlSpSessions;

   @Inject
   private Instance<SamlServiceProviderSpi> samlServiceProviderSpi;

   @Inject
   private Instance<SamlEntityBean> samlEntityBean;

   @Inject
   private DialogueBean dialogue;

   @Inject
   private SamlMessageSender samlMessageSender;

   @Inject
   private SamlDialogue samlDialogue;

   @Inject
   private SamlMessageFactory samlMessageFactory;

   @Inject
   private ResponseHandler responseHandler;

   public void processIDPResponse(HttpServletRequest httpRequest, HttpServletResponse httpResponse, StatusResponseType statusResponse) throws InvalidRequestException
   {
      SamlExternalIdentityProvider idp = (SamlExternalIdentityProvider) samlDialogue.getExternalProvider();

      StatusType status = statusResponse.getStatus();
      if (status == null)
      {
         throw new InvalidRequestException("Response does not contain a status");
      }

      String statusValue = status.getStatusCode().getValue();
      if (!SamlConstants.STATUS_SUCCESS.equals(statusValue))
      {
         String statusCodeLevel1 = statusValue;
         String statusCodeLevel2 = null;
         if (status.getStatusCode().getStatusCode() != null)
         {
            statusCodeLevel2 = status.getStatusCode().getStatusCode().getValue();
         }
         samlServiceProviderSpi.get().loginFailed(statusCodeLevel1, statusCodeLevel2, responseHandler.createResponseHolder(httpResponse));
      }

      if (!(statusResponse instanceof ResponseType))
      {
         throw new InvalidRequestException("Response does not have type ResponseType");
      }

      ResponseType response = (ResponseType) statusResponse;

      List<Object> assertions = response.getAssertionOrEncryptedAssertion();
      if (assertions.size() == 0)
      {
         throw new RuntimeException("IDP response does not contain assertions");
      }

      SamlSpSessionImpl session = createSession(response, idp);
      if (session == null)
      {
         throw new InvalidRequestException("Not possible to login based on the supplied assertions");
      }
      else
      {
         session.setIdentityProvider(idp);
         loginUser(httpRequest, httpResponse, session, statusResponse.getInResponseTo() == null, httpRequest.getParameter(SamlRedirectMessage.QSP_RELAY_STATE));
      }

      dialogue.setFinished(true);
   }

   private SamlSpSessionImpl createSession(ResponseType responseType, SamlExternalIdentityProvider idp)
   {
      SamlSpSessionImpl session = null;

      for (Object assertion : responseType.getAssertionOrEncryptedAssertion())
      {
         if (assertion instanceof AssertionType)
         {
            SamlSpSessionImpl sessionExtractedFromAssertion = handleAssertion((AssertionType) assertion, idp);
            if (session == null)
            {
               session = sessionExtractedFromAssertion;
            }
            else
            {
               log.warn("Multiple authenticated users found in assertions. Using the first one.");
            }
         }
         else
         {
            /* assertion instanceof EncryptedElementType */
            log.warn("Encountered encrypted assertion. Skipping it because decryption is not yet supported.");
         }
      }
      return session;
   }

   private SamlSpSessionImpl handleAssertion(AssertionType assertion, SamlExternalIdentityProvider idp)
   {
      if (SamlUtils.hasAssertionExpired(assertion))
      {
         log.warn("Received assertion not processed because it has expired.");
         return null;
      }

      AuthnStatementType authnStatement = extractValidAuthnStatement(assertion);
      if (authnStatement == null)
      {
         log.warn("Received assertion not processed because it doesn't contain a valid authnStatement.");
         return null;
      }

      NameIDType nameId = validateSubjectAndExtractNameID(assertion);
      if (nameId == null)
      {
         log.warn("Received assertion not processed because it doesn't contain a valid subject.");
         return null;
      }

      SamlPrincipalImpl principal = new SamlPrincipalImpl();
      principal.setAssertion(assertion);
      principal.setNameId(new SamlNameIdImpl(nameId.getValue(), nameId.getFormat(), nameId.getNameQualifier()));
      SamlSpSessionImpl session = new SamlSpSessionImpl();
      session.setSessionIndex(authnStatement.getSessionIndex());
      session.setPrincipal(principal);
      session.setIdentityProvider(idp);

      for (StatementAbstractType statement : assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement())
      {
         if (statement instanceof AttributeStatementType)
         {
            AttributeStatementType attributeStatement = (AttributeStatementType) statement;
            List<AttributeType> attributes = new LinkedList<AttributeType>();
            for (Object object : attributeStatement.getAttributeOrEncryptedAttribute())
            {
               if (object instanceof AttributeType)
               {
                  attributes.add((AttributeType) object);
               }
               else
               {
                  log.warn("Encrypted attributes are not supported. Ignoring the attribute.");
               }
            }
            principal.setAttributes(attributes);
         }
      }

      return session;
   }

   private AuthnStatementType extractValidAuthnStatement(AssertionType assertion)
   {
      for (StatementAbstractType statement : assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement())
      {
         if (statement instanceof AuthnStatementType)
         {
            AuthnStatementType authnStatement = (AuthnStatementType) statement;
            return authnStatement;
         }
      }

      return null;
   }

   private NameIDType validateSubjectAndExtractNameID(AssertionType assertion)
   {
      NameIDType nameId = null;
      boolean validConfirmationFound = false;

      for (JAXBElement<?> contentElement : assertion.getSubject().getContent())
      {
         if (contentElement.getValue() instanceof NameIDType)
         {
            nameId = (NameIDType) contentElement.getValue();
         }
         if (contentElement.getValue() instanceof SubjectConfirmationType)
         {
            SubjectConfirmationType confirmation = (SubjectConfirmationType) contentElement.getValue();
            if (confirmation.getMethod().equals(SamlConstants.CONFIRMATION_METHOD_BEARER))
            {
               SubjectConfirmationDataType confirmationData = confirmation.getSubjectConfirmationData();

               boolean validRecipient = confirmationData.getRecipient().equals(samlEntityBean.get().getServiceURL(SamlServiceType.SAML_ASSERTION_CONSUMER_SERVICE));

               boolean notTooLate = confirmationData.getNotOnOrAfter().compare(SamlUtils.getXMLGregorianCalendarNow()) == DatatypeConstants.GREATER;

               boolean validInResponseTo = confirmationData.getInResponseTo() == null || confirmationData.getInResponseTo().equals(dialogue.getId());

               if (validRecipient && notTooLate && validInResponseTo)
               {
                  validConfirmationFound = true;
               }
               else
               {
                  log.debugf("Validation of assertion failed: validRecipient: %b; notTootLate: %b; validInResponseTo: %b", new Object[] { validRecipient, notTooLate, validInResponseTo });
               }
            }
         }
      }

      if (validConfirmationFound)
      {
         return nameId;
      }
      else
      {
         return null;
      }
   }

   private void loginUser(HttpServletRequest httpRequest, HttpServletResponse response, SamlSpSessionImpl session, boolean unsolicited, String relayState)
   {
      samlSpSessions.addSession(session);

      if (unsolicited)
      {
         samlServiceProviderSpi.get().loggedIn(session, relayState, responseHandler.createResponseHolder(response));
      }
      else
      {
         samlServiceProviderSpi.get().loginSucceeded(session, responseHandler.createResponseHolder(response));
      }
   }

   public void sendAuthenticationRequestToIDP(SamlExternalIdentityProvider idp, HttpServletResponse response)
   {
      AuthnRequestType authnRequest = samlMessageFactory.createAuthnRequest();

      samlDialogue.setExternalProvider(idp);

      samlMessageSender.sendRequest(idp, SamlProfile.SINGLE_SIGN_ON, authnRequest, response);
   }
}
TOP

Related Classes of org.jboss.seam.security.external.saml.sp.SamlSpSingleSignOnService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.