Пример #1
0
        /// <summary>
        /// Handles all artifact creations and redirects.
        /// </summary>
        /// <param name="destination">The destination.</param>
        /// <param name="localEndpointIndex">Index of the local endpoint.</param>
        /// <param name="signedSamlMessage">The signed saml message.</param>
        /// <param name="relayState">The query string relay state value to add to the communication</param>
        private void ArtifactRedirect(IDPEndPointElement destination, Int16 localEndpointIndex, XmlDocument signedSamlMessage, string relayState)
        {
            SAML20FederationConfig config = SAML20FederationConfig.GetConfig();
            string sourceId = config.ServiceProvider.ID;
            byte[] sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceId);
            byte[] messageHandle = ArtifactUtil.GenerateMessageHandle();

            string artifact = ArtifactUtil.CreateArtifact(HttpArtifactBindingConstants.ArtifactTypeCode, localEndpointIndex, sourceIdHash, messageHandle);

            _context.Cache.Insert(artifact, signedSamlMessage, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration);

            string destinationUrl = destination.Url + "?" + HttpArtifactBindingConstants.ArtifactQueryStringName + "=" +
                                    HttpUtility.UrlEncode(artifact);
            if (!string.IsNullOrEmpty(relayState))
            {
                destinationUrl += "&relayState=" + relayState;
            }

            if(Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.CreatedArtifact, artifact, signedSamlMessage.OuterXml));
            }

            _context.Response.Redirect(destinationUrl);
        }
Пример #2
0
        /// <summary>
        /// Parses the metadata files found in the directory specified in the configuration.
        /// </summary>
        private Saml20MetadataDocument ParseFile(string file)
        {
            XmlDocument doc = LoadFileAsXmlDocument(file);

            //_fileInfo[file] = File.GetLastWriteTime(file); // Mark that we have seen the file.
            try
            {
                foreach (XmlNode child in doc.ChildNodes)
                {
                    if (child.NamespaceURI == Saml20Constants.METADATA)
                    {
                        if (child.LocalName == EntityDescriptor.ELEMENT_NAME)
                        {
                            return(new Saml20MetadataDocument(doc));
                        }

                        // TODO Decide how to handle several entities in one metadata file.
                        if (child.LocalName == EntitiesDescriptor.ELEMENT_NAME)
                        {
                            throw new NotImplementedException();
                        }
                    }
                }

                // No entity descriptor found.
                throw new InvalidDataException(); // BAIIIIIIL!!
            } catch (Exception e)
            {
                // Probably not a metadata file.
                Trace.TraceData(TraceEventType.Error, file, "Probably not a SAML2.0 metadata file.", e.ToString());
                return(null);
            }
        }
Пример #3
0
        /// <summary>
        /// Decrypts an encrypted assertion, and sends the result to the HandleAssertion method.
        /// </summary>
        private void HandleEncryptedAssertion(HttpContext context, XmlElement elem)
        {
            Trace.TraceMethodCalled(GetType(), "HandleEncryptedAssertion()");
            Saml20EncryptedAssertion decryptedAssertion = GetDecryptedAssertion(elem);

            HandleAssertion(context, decryptedAssertion.Assertion.DocumentElement);
        }
Пример #4
0
        /// <summary>
        /// Send an authentication request to the IDP.
        /// </summary>
        private void SendRequest(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "SendRequest()");

            // See if the "ReturnUrl" - parameter is set.
            string returnUrl = context.Request.QueryString["ReturnUrl"];

            // If PreventOpenRedirectAttack has been enabled ... the return URL is only set if the URL is local.
            if (!string.IsNullOrEmpty(returnUrl) && (!FederationConfig.GetConfig().PreventOpenRedirectAttack || IsLocalUrl(returnUrl)))
            {
                SessionFactory.SessionContext.Current[SessionConstants.RedirectUrl] = returnUrl;
            }

            IDPEndPoint idpEndpoint = RetrieveIDP(context);

            if (idpEndpoint == null)
            {
                //Display a page to the user where she can pick the IDP
                SelectSaml20IDP page = new SelectSaml20IDP();
                page.ProcessRequest(context);
                return;
            }

            Saml20AuthnRequest authnRequest = Saml20AuthnRequest.GetDefault();

            TransferClient(idpEndpoint, authnRequest, context);
        }
        /// <summary>
        /// Handles a request.
        /// </summary>
        /// <param name="context">The context.</param>
        protected override void Handle(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "Handle()");

            try
            {
                //Some IdP's are known to fail to set an actual value in the SOAPAction header
                //so we just check for the existence of the header field.
                if (Array.Exists(context.Request.Headers.AllKeys, delegate(string s) { return(s == SOAPConstants.SOAPAction); }))
                {
                    HandleSOAP(context, context.Request.InputStream);
                    return;
                }

                if (!string.IsNullOrEmpty(context.Request.Params["SAMLart"]))
                {
                    HandleArtifact(context);
                    return;
                }

                if (!string.IsNullOrEmpty(context.Request.Params["SAMLResponse"]))
                {
                    HandleResponse(context);
                }
                else if (!string.IsNullOrEmpty(context.Request.Params["SAMLRequest"]))
                {
                    HandleRequest(context);
                }
                else
                {
                    IDPEndPoint         idpEndpoint         = null;
                    Saml20AssertionLite saml20AssertionLite = Saml20PrincipalCache.GetSaml20AssertionLite();
                    if (saml20AssertionLite != null)
                    {
                        idpEndpoint = RetrieveIDPConfiguration(saml20AssertionLite.Issuer);
                    }

                    if (idpEndpoint == null)
                    {
                        context.User = null;
                        FormsAuthentication.SignOut();
                        HandleError(context, Resources.UnknownLoginIDP);
                    }

                    TransferClient(idpEndpoint, context);
                }
            }
            catch (Exception e)
            {
                //ThreadAbortException is thrown by response.Redirect so don't worry about it
                if (e is ThreadAbortException)
                {
                    throw;
                }

                HandleError(context, e.Message);
            }
        }
Пример #6
0
        /// <summary>
        /// Is called before the assertion is made into a strongly typed representation
        /// </summary>
        /// <param name="context">The httpcontext.</param>
        /// <param name="elem">The assertion element.</param>
        /// <param name="endpoint">The endpoint.</param>
        protected virtual void PreHandleAssertion(HttpContext context, XmlElement elem, IDPEndPoint endpoint)
        {
            Trace.TraceMethodCalled(GetType(), "PreHandleAssertion");

            if (endpoint != null && endpoint.SLOEndpoint != null && !String.IsNullOrEmpty(endpoint.SLOEndpoint.IdpTokenAccessor))
            {
                ISaml20IdpTokenAccessor idpTokenAccessor =
                    Activator.CreateInstance(Type.GetType(endpoint.SLOEndpoint.IdpTokenAccessor, false)) as ISaml20IdpTokenAccessor;
                if (idpTokenAccessor != null)
                {
                    idpTokenAccessor.ReadToken(elem);
                }
            }

            Trace.TraceMethodDone(GetType(), "PreHandleAssertion");
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="Saml20LogoutHandler"/> class.
 /// </summary>
 public Saml20LogoutHandler()
 {
     // Read the proper redirect url from config
     try
     {
         RedirectUrl    = SAML20FederationConfig.GetConfig().ServiceProvider.LogoutEndpoint.RedirectUrl;
         ErrorBehaviour = SAML20FederationConfig.GetConfig().ServiceProvider.LogoutEndpoint.ErrorBehaviour.ToString();
     }
     catch (Exception e)
     {
         if (Trace.ShouldTrace(TraceEventType.Error))
         {
             Trace.TraceData(TraceEventType.Error, e.ToString());
         }
     }
 }
Пример #8
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Saml20SignonHandler"/> class.
        /// </summary>
        public Saml20SignonHandler()
        {
            _certificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate();

            // Read the proper redirect url from config
            try
            {
                RedirectUrl    = SAML20FederationConfig.GetConfig().ServiceProvider.SignOnEndpoint.RedirectUrl;
                ErrorBehaviour = SAML20FederationConfig.GetConfig().ServiceProvider.SignOnEndpoint.ErrorBehaviour.ToString();
            }
            catch (Exception e)
            {
                if (Trace.ShouldTrace(TraceEventType.Error))
                {
                    Trace.TraceData(TraceEventType.Error, e.ToString());
                }
            }
        }
Пример #9
0
        private static XmlDocument GetDecodedSamlResponse(HttpContext context, Encoding encoding)
        {
            string base64 = context.Request.Params["SAMLResponse"];

            XmlDocument doc = new XmlDocument();

            doc.XmlResolver        = null;
            doc.PreserveWhitespace = true;
            string samlResponse = encoding.GetString(Convert.FromBase64String(base64));

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, "Decoded SAMLResponse", samlResponse);
            }

            doc.LoadXml(samlResponse);
            return(doc);
        }
Пример #10
0
 public void Load(string base64AuthorisationsAttribute)
 {
     try
     {
         string             decoded        = Encoding.UTF8.GetString(Convert.FromBase64String(base64AuthorisationsAttribute));
         AuthorisationsType authorisations = Serialization.DeserializeFromXmlString <AuthorisationsType>(decoded);
         _autorisations = authorisations;
         _isLoaded      = true;
     }
     catch (Exception e)
     {
         _isLoaded = false;
         if (Trace.ShouldTrace(TraceEventType.Error))
         {
             Trace.TraceData(TraceEventType.Error, string.Format(Errors.DecodeFailed, base64AuthorisationsAttribute, e.Message));
         }
         throw new Saml20BRSException(Errors.DecodeFailedMsg, e);
     }
 }
        /// <summary>
        /// Performs the attribute query and adds the resulting attributes to Saml20Identity.Current.
        /// </summary>
        /// <param name="context">The http context.</param>
        public void PerformQuery(HttpContext context)
        {
            SAML20FederationConfig config = SAML20FederationConfig.GetConfig();
            string endpointId             = Saml20PrincipalCache.GetSaml20AssertionLite().Issuer;

            if (string.IsNullOrEmpty(endpointId))
            {
                Trace.TraceData(TraceEventType.Information, Tracing.AttrQueryNoLogin);
                throw new InvalidOperationException(Tracing.AttrQueryNoLogin);
            }

            IDPEndPoint ep = config.FindEndPoint(endpointId);

            if (ep == null)
            {
                throw new Saml20Exception(string.Format("Unable to find information about the IdP with id \"{0}\"", endpointId));
            }

            PerformQuery(context, ep);
        }
        private void DoSoapLogout(HttpContext context, string userId)
        {
            try
            {
                foreach (IAction action in Actions.Actions.GetActions())
                {
                    Trace.TraceMethodCalled(action.GetType(), "SoapLogoutAction()");

                    action.SoapLogoutAction(this, context, userId);

                    Trace.TraceMethodDone(action.GetType(), "SoapLogoutAction()");
                }
            }
            finally
            {
                // Always end with abandoning the session.
                Trace.TraceData(TraceEventType.Information, "Clearing all sessions related to user with id: " + userId);
                SessionFactory.SessionContext.AbandonAllSessions(userId);
                Trace.TraceData(TraceEventType.Verbose, "Sessions cleared.");
            }
        }
Пример #13
0
        /// <summary>
        /// Handles a request.
        /// </summary>
        /// <param name="context">The context.</param>
        protected override void Handle(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "Handle()");



            //Some IdP's are known to fail to set an actual value in the SOAPAction header
            //so we just check for the existence of the header field.
            if (Array.Exists(context.Request.Headers.AllKeys, delegate(string s) { return(s == SOAPConstants.SOAPAction); }))
            {
                HandleSOAP(context, context.Request.InputStream);
                return;
            }

            if (!string.IsNullOrEmpty(context.Request.Params["SAMLart"]))
            {
                HandleArtifact(context);
            }

            if (!string.IsNullOrEmpty(context.Request.Params["SamlResponse"]))
            {
                HandleResponse(context);
            }
            else
            {
                if (SAML20FederationConfig.GetConfig().CommonDomain.Enabled&& context.Request.QueryString["r"] == null &&
                    context.Request.Params["cidp"] == null)
                {
                    AuditLogging.logEntry(Direction.OUT, Operation.DISCOVER, "Redirecting to Common Domain for IDP discovery");
                    context.Response.Redirect(SAML20FederationConfig.GetConfig().CommonDomain.LocalReaderEndpoint);
                }
                else
                {
                    AuditLogging.logEntry(Direction.IN, Operation.ACCESS,
                                          "User accessing resource: " + context.Request.RawUrl +
                                          " without authentication.");
                    SendRequest(context);
                }
            }
        }
        private void DoLogout(HttpContext context, bool IdPInitiated)
        {
            try
            {
                foreach (IAction action in Actions.Actions.GetActions())
                {
                    Trace.TraceMethodCalled(action.GetType(), "LogoutAction()");

                    action.LogoutAction(this, context, IdPInitiated);

                    Trace.TraceMethodDone(action.GetType(), "LogoutAction()");
                }
            }
            finally
            {
                // Always end with abandoning the session.
                Trace.TraceData(TraceEventType.Information, "Clearing session with id: " + SessionFactory.SessionContext.Current.Id);
                SessionFactory.SessionContext.AbandonAllSessions(Saml20Identity.Current.Name);
                //SessionFactory.SessionContext.AbandonCurrentSession();
                Trace.TraceData(TraceEventType.Verbose, "Session cleared.");
            }
        }
Пример #15
0
        /// <summary>
        /// Handles responses to an artifact resolve message.
        /// </summary>
        /// <param name="artifactResolve">The artifact resolve message.</param>
        public void RespondToArtifactResolve(ArtifactResolve artifactResolve)
        {
            XmlDocument samlDoc = (XmlDocument)_context.Cache.Get(artifactResolve.Artifact);
            
            Saml20ArtifactResponse response = Saml20ArtifactResponse.GetDefault();
            response.StatusCode = Saml20Constants.StatusCodes.Success;
            response.InResponseTo = artifactResolve.ID;
            response.SamlElement = samlDoc.DocumentElement;

            XmlDocument responseDoc = response.GetXml();

            if (responseDoc.FirstChild is XmlDeclaration)
                responseDoc.RemoveChild(responseDoc.FirstChild);

            XmlSignatureUtils.SignDocument(responseDoc, response.ID);

            if(Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.RespondToArtifactResolve, artifactResolve.Artifact, responseDoc.OuterXml));
            }
            SendResponseMessage(responseDoc.OuterXml);
        }
Пример #16
0
        private void DoLogin(HttpContext context, Saml20Assertion assertion)
        {
            SessionFactory.SessionContext.AssociateUserIdWithCurrentSession(assertion.Subject.Value);
            SessionFactory.SessionContext.Current[SessionConstants.Saml20AssertionLite] = Saml20AssertionLite.ToLite(assertion);

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.Login, assertion.Subject.Value, assertion.SessionIndex, assertion.Subject.Format));
            }

            string assuranceLevel = GetAssuranceLevel(assertion) ?? "(Unknown)";

            AuditLogging.logEntry(Direction.IN, Operation.LOGIN, string.Format("Subject: {0} NameIDFormat: {1}  Level of authentication: {2}  Session timeout in minutes: {3}", assertion.Subject.Value, assertion.Subject.Format, assuranceLevel, FederationConfig.GetConfig().SessionTimeout));


            foreach (IAction action in Actions.Actions.GetActions())
            {
                Trace.TraceMethodCalled(action.GetType(), "LoginAction()");

                action.LoginAction(this, context, assertion);

                Trace.TraceMethodDone(action.GetType(), "LoginAction()");
            }
        }
Пример #17
0
        /// <summary>
        /// Resolves an artifact.
        /// </summary>
        /// <returns>A stream containing the artifact response from the IdP</returns>
        public Stream ResolveArtifact()
        {
            Trace.TraceMethodCalled(GetType(), "ResolveArtifact()");

            string artifact = _context.Request.Params["SAMLart"];

            IDPEndPoint idpEndPoint = DetermineIdp(artifact);

            if (idpEndPoint == null)
                throw new InvalidOperationException("Received artifact from unknown IDP.");

            ushort endpointIndex = ArtifactUtil.GetEndpointIndex(artifact);

            string endpointUrl = idpEndPoint.metadata.GetARSEndpoint(endpointIndex);

            Saml20ArtifactResolve resolve = Saml20ArtifactResolve.GetDefault();

            resolve.Artifact = artifact;

            XmlDocument doc = resolve.GetXml();

            if (doc.FirstChild is XmlDeclaration)
                doc.RemoveChild(doc.FirstChild);

            XmlSignatureUtils.SignDocument(doc, resolve.ID);

            string artifactResolveString = doc.OuterXml;

            if(Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.ResolveArtifact, artifact, idpEndPoint.Id, endpointIndex, endpointUrl, artifactResolveString));
            }

            return GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution);
            
        }
        /// <summary>
        /// Performs the attribute query against the specified IdP endpoint and adds the resulting attributes to Saml20Identity.Current.
        /// </summary>
        /// <param name="context">The http context.</param>
        /// <param name="endPoint">The IdP to perform the query against.</param>
        /// <param name="nameIdFormat">The nameid format.</param>
        public void PerformQuery(HttpContext context, IDPEndPoint endPoint, string nameIdFormat)
        {
            Trace.TraceMethodCalled(GetType(), "PerformQuery()");

            HttpSOAPBindingBuilder builder = new HttpSOAPBindingBuilder(context);

            NameID name = new NameID();

            name.Value  = Saml20Identity.Current.Name;
            name.Format = nameIdFormat;
            _attrQuery.Subject.Items = new object[] { name };

            _attrQuery.SamlAttribute = _attributes.ToArray();
            XmlDocument query = new XmlDocument();

            query.XmlResolver = null;
            query.LoadXml(Serialization.SerializeToXmlString(_attrQuery));

            XmlSignatureUtils.SignDocument(query, ID);
            if (query.FirstChild is XmlDeclaration)
            {
                query.RemoveChild(query.FirstChild);
            }

            Stream s;

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAttrQuery, endPoint.metadata.GetAttributeQueryEndpointLocation(), query.OuterXml));
            }

            try
            {
                s = builder.GetResponse(endPoint.metadata.GetAttributeQueryEndpointLocation(), query.OuterXml,
                                        endPoint.AttributeQuery);
            }
            catch (Exception e)
            {
                Trace.TraceData(TraceEventType.Error, e.ToString());
                throw;
            }

            HttpSOAPBindingParser parser = new HttpSOAPBindingParser(s);

            Status status = parser.GetStatus();

            if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
            {
                Trace.TraceData(TraceEventType.Error,
                                string.Format(Tracing.AttrQueryStatusError, Serialization.SerializeToXmlString(status)));
                throw new Saml20Exception(status.StatusMessage);
            }

            bool isEncrypted;

            XmlElement xmlAssertion = Saml20SignonHandler.GetAssertion(parser.SamlMessage, out isEncrypted);

            if (isEncrypted)
            {
                Saml20EncryptedAssertion ass =
                    new Saml20EncryptedAssertion(
                        (RSA)FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey);
                ass.LoadXml(xmlAssertion);
                ass.Decrypt();
                xmlAssertion = ass.Assertion.DocumentElement;
            }

            Saml20Assertion assertion =
                new Saml20Assertion(xmlAssertion, null,
                                    AssertionProfile.Core, endPoint.QuirksMode);

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.AttrQueryAssertion, xmlAssertion == null ? string.Empty : xmlAssertion.OuterXml));
            }

            if (!assertion.CheckSignature(Saml20SignonHandler.GetTrustedSigners(endPoint.metadata.Keys, endPoint)))
            {
                Trace.TraceData(TraceEventType.Error, Resources.SignatureInvalid);
                throw new Saml20Exception(Resources.SignatureInvalid);
            }

            foreach (SamlAttribute attr in assertion.Attributes)
            {
                Saml20Identity.Current.AddAttributeFromQuery(attr.Name, attr);
            }
        }
        private void HandleRequest(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "HandleRequest()");

            //Fetch config object
            SAML20FederationConfig config = SAML20FederationConfig.GetConfig();

            LogoutRequest logoutRequest = null;
            IDPEndPoint   endpoint      = null;
            string        message       = string.Empty;

            //Build the response object
            var response = new Saml20LogoutResponse();

            response.Issuer     = config.ServiceProvider.ID;
            response.StatusCode = Saml20Constants.StatusCodes.Success; // Default success. Is overwritten if something fails.

            if (context.Request.RequestType == "GET")                  // HTTP Redirect binding
            {
                HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url);
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST,
                                      string.Format("Binding: redirect, Signature algorithm: {0}  Signature:  {1}, Message: {2}", parser.SignatureAlgorithm, parser.Signature, parser.Message));

                if (!parser.IsSigned)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                logoutRequest = parser.LogoutRequest;
                endpoint      = config.FindEndPoint(logoutRequest.Issuer.Value);

                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + logoutRequest.Issuer.Value);
                    // Not able to return a response as we do not know the IdP.
                    HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature redirect-binding, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                message = parser.Message;
            }
            else if (context.Request.RequestType == "POST") // HTTP Post binding
            {
                HttpPostBindingParser parser = new HttpPostBindingParser(context);
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST,
                                      "Binding: POST, Message: " + parser.Message);

                if (!parser.IsSigned())
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                logoutRequest = parser.LogoutRequest;
                endpoint      = config.FindEndPoint(logoutRequest.Issuer.Value);
                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP");
                    // Not able to return a response as we do not know the IdP.
                    HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                // handle a logout-request
                if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature post-binding, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                message = parser.Message;
            }
            else
            {
                //Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS
                // Not able to return a response as we do not understand the request.
                HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType));
            }

            AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, message);

            // Check that idp in session and request matches.
            string idpRequest = logoutRequest.Issuer.Value;

            // SessionFactory.SessionContext.Current.New is never the first call to Current due to the logic in Application_AuthenticateRequest() ... Saml20Identity.IsInitialized()
            // Hence we need to check on Saml20Identity.IsInitialized() instead of using SessionFactory.SessionContext.Current.New.
            bool isOioSamlSessionActive = Saml20Identity.IsInitialized();

            if (isOioSamlSessionActive)
            {
                object idpId = Saml20PrincipalCache.GetSaml20AssertionLite().Issuer;

                if (idpId != null && idpId.ToString() != idpRequest)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, Resources.IdPMismatchBetweenRequestAndSessionFormat(idpId, idpRequest), message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }
            }
            else
            {
                // All other status codes than Success results in the IdP throwing an error page. Therefore we return default Success even if we do not have a session.
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Session does not exist. Continues the redirect logout procedure with status code success." + idpRequest, message);
            }

            //  Only logout if request is valid and we are working on an existing Session.
            if (Saml20Constants.StatusCodes.Success == response.StatusCode && isOioSamlSessionActive)
            {
                // Execute all actions that the service provider has configured
                DoLogout(context, true);
            }

            // Update the response object with informations that first is available when request has been parsed.
            IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints());

            response.Destination  = destination.Url;
            response.InResponseTo = logoutRequest.ID;

            //Respond using redirect binding
            if (destination.Binding == SAMLBinding.REDIRECT)
            {
                HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder();
                builder.RelayState = context.Request.Params["RelayState"];
                builder.Response   = response.GetXml().OuterXml;
                builder.signingKey = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey;
                string s = destination.Url + "?" + builder.ToQuery();
                context.Response.Redirect(s, true);
                return;
            }

            //Respond using post binding
            if (destination.Binding == SAMLBinding.POST)
            {
                HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination);
                builder.Action = SAMLAction.SAMLResponse;
                XmlDocument responseDocument = response.GetXml();
                XmlSignatureUtils.SignDocument(responseDocument, response.ID);
                builder.Response   = responseDocument.OuterXml;
                builder.RelayState = context.Request.Params["RelayState"];
                builder.GetPage().ProcessRequest(context);
                return;
            }
        }
        private void HandleResponse(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "HandleResponse()");


            string message = string.Empty;

            if (context.Request.RequestType == "GET")
            {
                HttpRedirectBindingParser parser   = new HttpRedirectBindingParser(context.Request.Url);
                LogoutResponse            response = Serialization.DeserializeFromXmlString <LogoutResponse>(parser.Message);

                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                      string.Format("Binding: redirect, Signature algorithm: {0}  Signature:  {1}, Message: {2}", parser.SignatureAlgorithm, parser.Signature, parser.Message));

                IDPEndPoint idp = RetrieveIDPConfiguration(response.Issuer.Value);

                AuditLogging.IdpId       = idp.Id;
                AuditLogging.AssertionId = response.ID;

                if (idp.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                          string.Format("No IDP metadata, unknown IDP, response: {0}", parser.Message));
                    HandleError(context, Resources.UnknownIDP);
                    return;
                }

                if (!parser.VerifySignature(idp.metadata.Keys))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                          string.Format("Invalid signature in redirect-binding, response: {0}", parser.Message));
                    HandleError(context, Resources.SignatureInvalid);
                    return;
                }

                message = parser.Message;
            }
            else if (context.Request.RequestType == "POST")
            {
                HttpPostBindingParser parser = new HttpPostBindingParser(context);
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                      "Binding: POST, Message: " + parser.Message);


                LogoutResponse response = Serialization.DeserializeFromXmlString <LogoutResponse>(parser.Message);

                IDPEndPoint idp = RetrieveIDPConfiguration(response.Issuer.Value);

                if (idp.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                          string.Format("No IDP metadata, unknown IDP, response: {0}", parser.Message));
                    HandleError(context, Resources.UnknownIDP);
                    return;
                }

                if (!parser.IsSigned())
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                          string.Format("Signature not present, response: {0}", parser.Message));
                    HandleError(context, Resources.SignatureNotPresent);
                }

                // signature on final message in logout
                if (!parser.CheckSignature(idp.metadata.Keys))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                          string.Format("Invalid signature in post-binding, response: {0}", parser.Message));
                    HandleError(context, Resources.SignatureInvalid);
                }

                message = parser.Message;
            }
            else
            {
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                      string.Format("Unsupported request type format, type: {0}", context.Request.RequestType));
                HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType));
            }

            XmlDocument doc = new XmlDocument();

            doc.XmlResolver        = null;
            doc.PreserveWhitespace = true;
            doc.LoadXml(message);

            XmlElement statElem =
                (XmlElement)doc.GetElementsByTagName(Status.ELEMENT_NAME, Saml20Constants.PROTOCOL)[0];

            Status status = Serialization.DeserializeFromXmlString <Status>(statElem.OuterXml);

            if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
            {
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                      string.Format("Unexpected status code: {0}, msg: {1}", status.StatusCode.Value, message));
                HandleError(context, status);
                return;
            }

            AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE,
                                  "Assertion validated succesfully");

            //Log the user out locally
            DoLogout(context);
        }
Пример #21
0
        private void HandleSOAP(HttpContext context, Stream inputStream)
        {
            Trace.TraceMethodCalled(GetType(), "HandleSOAP");
            HttpArtifactBindingParser  parser  = new HttpArtifactBindingParser(inputStream);
            HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context);

            if (parser.IsArtifactResolve())
            {
                Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResolveIn);

                IDPEndPoint idp = RetrieveIDPConfiguration(parser.Issuer);
                AuditLogging.IdpId       = idp.Id;
                AuditLogging.AssertionId = parser.ArtifactResolve.ID;
                if (!parser.CheckSamlMessageSignature(idp.metadata.Keys))
                {
                    HandleError(context, "Invalid Saml message signature");
                    AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, "Could not verify signature", parser.SamlMessage);
                }
                builder.RespondToArtifactResolve(parser.ArtifactResolve);
            }
            else if (parser.IsArtifactResponse())
            {
                Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResponseIn);

                Status status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                {
                    HandleError(context, status);
                    AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, string.Format("Illegal status for ArtifactResponse {0} expected 'Success', msg: {1}", status.StatusCode.Value, parser.SamlMessage));
                    return;
                }
                if (parser.ArtifactResponse.Any.LocalName == Response.ELEMENT_NAME)
                {
                    bool       isEncrypted;
                    XmlElement assertion = GetAssertion(parser.ArtifactResponse.Any, out isEncrypted);
                    if (assertion == null)
                    {
                        HandleError(context, "Missing assertion");
                    }
                    if (isEncrypted)
                    {
                        HandleEncryptedAssertion(context, assertion);
                    }
                    else
                    {
                        HandleAssertion(context, assertion);
                    }
                }
                else
                {
                    AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, string.Format("Unsupported payload message in ArtifactResponse: {0}, msg: {1}", parser.ArtifactResponse.Any.LocalName, parser.SamlMessage));
                    HandleError(context,
                                string.Format("Unsupported payload message in ArtifactResponse: {0}",
                                              parser.ArtifactResponse.Any.LocalName));
                }
            }
            else
            {
                Status s = parser.GetStatus();
                if (s != null)
                {
                    HandleError(context, s);
                }
                else
                {
                    AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, string.Format("Unsupported SamlMessage element: {0}, msg: {1}", parser.SamlMessageName, parser.SamlMessage));
                    HandleError(context, string.Format("Unsupported SamlMessage element: {0}", parser.SamlMessageName));
                }
            }
        }
        private void TransferClient(IDPEndPoint endpoint, HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "TransferClient()");

            Saml20LogoutRequest request = Saml20LogoutRequest.GetDefault();

            AuditLogging.AssertionId = request.ID;
            AuditLogging.IdpId       = endpoint.Id;

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            IDPEndPointElement destination =
                DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints());

            request.Destination = destination.Url;

            request.SubjectToLogOut.Format = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Format;

            if (destination.Binding == SAMLBinding.POST)
            {
                HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination);
                request.Destination           = destination.Url;
                request.Reason                = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Value;
                request.SessionIndex          = Saml20PrincipalCache.GetSaml20AssertionLite().SessionIndex;
                XmlDocument requestDocument = request.GetXml();
                XmlSignatureUtils.SignDocument(requestDocument, request.ID);
                builder.Request = requestDocument.OuterXml;

                if (Trace.ShouldTrace(TraceEventType.Information))
                {
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "POST", endpoint.Id, requestDocument.OuterXml));
                }

                AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Binding: POST");
                builder.GetPage().ProcessRequest(context);
                context.Response.End();
                return;
            }

            if (destination.Binding == SAMLBinding.REDIRECT)
            {
                HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder();
                builder.signingKey            = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey;
                request.Destination           = destination.Url;
                request.Reason                = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Value;
                request.SessionIndex          = Saml20PrincipalCache.GetSaml20AssertionLite().SessionIndex;
                builder.Request               = request.GetXml().OuterXml;

                string redirectUrl = destination.Url + "?" + builder.ToQuery();

                if (Trace.ShouldTrace(TraceEventType.Information))
                {
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "REDIRECT", endpoint.Id, redirectUrl));
                }

                AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Binding: Redirect");
                context.Response.Redirect(redirectUrl, true);
                return;
            }

            if (destination.Binding == SAMLBinding.ARTIFACT)
            {
                if (Trace.ShouldTrace(TraceEventType.Information))
                {
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "ARTIFACT", endpoint.Id, string.Empty));
                }

                request.Destination           = destination.Url;
                request.Reason                = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Value;
                request.SessionIndex          = Saml20PrincipalCache.GetSaml20AssertionLite().SessionIndex;

                HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context);
                AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Method: Artifact");
                builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N"));
            }

            HandleError(context, Resources.BindingError);
        }
        private void HandleSOAP(HttpContext context, Stream inputStream)
        {
            Trace.TraceMethodCalled(GetType(), "HandleSOAP");

            HttpArtifactBindingParser  parser  = new HttpArtifactBindingParser(inputStream);
            HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context);
            SAML20FederationConfig     config  = SAML20FederationConfig.GetConfig();

            IDPEndPoint idp = RetrieveIDPConfiguration(parser.Issuer);

            AuditLogging.IdpId = idp.Id;


            if (parser.IsArtifactResolve())
            {
                Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResolveIn);

                if (!parser.CheckSamlMessageSignature(idp.metadata.Keys))
                {
                    HandleError(context, "Invalid Saml message signature");
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, "Signature could not be verified", parser.SamlMessage);
                }
                AuditLogging.AssertionId = parser.ArtifactResolve.ID;
                AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, "", parser.SamlMessage);
                builder.RespondToArtifactResolve(parser.ArtifactResolve);
            }
            else if (parser.IsArtifactResponse())
            {
                Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResponseIn);

                Status status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                {
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unexpected status code for artifact response: {0}, expected 'Success', msg: {1}", status.StatusCode.Value, parser.SamlMessage));
                    HandleError(context, status);
                    return;
                }

                if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ELEMENT_NAME)
                {
                    if (Trace.ShouldTrace(TraceEventType.Information))
                    {
                        Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.ArtifactResponse.Any.OuterXml));
                    }

                    //Send logoutresponse via artifact
                    Saml20LogoutResponse response = new Saml20LogoutResponse();
                    response.Issuer = config.ServiceProvider.ID;
                    LogoutRequest req = Serialization.DeserializeFromXmlString <LogoutRequest>(parser.ArtifactResponse.Any.OuterXml);
                    response.StatusCode   = Saml20Constants.StatusCodes.Success;
                    response.InResponseTo = req.ID;
                    Saml20AssertionLite saml20AssertionLite = Saml20PrincipalCache.GetSaml20AssertionLite();
                    IDPEndPoint         endpoint            = RetrieveIDPConfiguration(saml20AssertionLite.Issuer);
                    IDPEndPointElement  destination         =
                        DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints());

                    builder.RedirectFromLogout(destination, response);
                }
                else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ELEMENT_NAME)
                {
                    DoLogout(context);
                }
                else
                {
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported payload message in ArtifactResponse: {0}, msg: {1}", parser.ArtifactResponse.Any.LocalName, parser.SamlMessage));
                    HandleError(context,
                                string.Format("Unsupported payload message in ArtifactResponse: {0}",
                                              parser.ArtifactResponse.Any.LocalName));
                }
            }
            else if (parser.IsLogoutReqest())
            {
                if (Trace.ShouldTrace(TraceEventType.Information))
                {
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.SamlMessage.OuterXml));
                }

                Saml20LogoutResponse response = new Saml20LogoutResponse();

                if (!parser.IsSigned())
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present in SOAP logout request, msg: " + parser.SamlMessage.OuterXml);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                if (idp.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + parser.Issuer);
                    // Not able to process the request as we do not know the IdP.
                    response.StatusCode = Saml20Constants.StatusCodes.NoAvailableIDP;
                }
                else
                {
                    Saml20MetadataDocument metadata = idp.metadata;

                    if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing)))
                    {
                        AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature SOAP logout, msg: " + parser.SamlMessage.OuterXml);
                        response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                    }
                }

                if (parser.GetNameID() != null && !string.IsNullOrEmpty(parser.GetNameID().Value))
                {
                    DoSoapLogout(context, parser.GetNameID().Value);
                }
                else
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. No user ID was supplied in SOAP logout request, msg: " + parser.SamlMessage.OuterXml);
                    response.StatusCode = Saml20Constants.StatusCodes.NoAuthnContext;
                }

                LogoutRequest req = parser.LogoutRequest;

                //Build the response object
                response.Issuer       = config.ServiceProvider.ID;
                response.StatusCode   = Saml20Constants.StatusCodes.Success;
                response.InResponseTo = req.ID;
                XmlDocument doc = response.GetXml();
                XmlSignatureUtils.SignDocument(doc, response.ID);
                if (doc.FirstChild is XmlDeclaration)
                {
                    doc.RemoveChild(doc.FirstChild);
                }

                builder.SendResponseMessage(doc.OuterXml);
            }
            else
            {
                Status s = parser.GetStatus();
                if (s != null)
                {
                    HandleError(context, s);
                }
                else
                {
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported SamlMessage element: {0}, msg: {1}", parser.SamlMessageName, parser.SamlMessage));
                    HandleError(context, string.Format("Unsupported SamlMessage element: {0}", parser.SamlMessageName));
                }
            }
        }
Пример #24
0
        /// <summary>
        /// Deserializes an assertion, verifies its signature and logs in the user if the assertion is valid.
        /// </summary>
        private void HandleAssertion(HttpContext context, XmlElement elem)
        {
            Trace.TraceMethodCalled(GetType(), "HandleAssertion");

            string issuer = GetIssuer(elem);

            IDPEndPoint endp = RetrieveIDPConfiguration(issuer);

            AuditLogging.IdpId = endp.Id;

            PreHandleAssertion(context, elem, endp);

            bool quirksMode = false;

            if (endp != null)
            {
                quirksMode = endp.QuirksMode;
            }

            Saml20Assertion assertion = new Saml20Assertion(elem, null, quirksMode);

            if (endp == null || endp.metadata == null)
            {
                AuditLogging.logEntry(Direction.IN, Operation.AUTHNREQUEST_POST,
                                      "Unknown login IDP, assertion: " + elem);

                HandleError(context, Resources.UnknownLoginIDP);
                return;
            }

            if (!endp.OmitAssertionSignatureCheck)
            {
                if (!assertion.CheckSignature(GetTrustedSigners(endp.metadata.GetKeys(KeyTypes.signing), endp)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.AUTHNREQUEST_POST,
                                          "Invalid signature, assertion: " + elem);

                    HandleError(context, Resources.SignatureInvalid);
                    return;
                }
            }

            if (assertion.IsExpired())
            {
                AuditLogging.logEntry(Direction.IN, Operation.AUTHNREQUEST_POST,
                                      "Assertion expired, assertion: " + elem.OuterXml);

                HandleError(context, Resources.AssertionExpired);
                return;
            }

            // Only check if assertion has the required assurancelevel if it is present.
            string assuranceLevel        = GetAssuranceLevel(assertion);
            string minimumAssuranceLevel = SAML20FederationConfig.GetConfig().MinimumAssuranceLevel;

            if (assuranceLevel != null)
            {
                // Assurance level is ok if the string matches the configured minimum assurance level. This is in order to support the value "Test". However, normally the value will be an integer
                if (assuranceLevel != minimumAssuranceLevel)
                {
                    // If strings are different it is still ok if the assertion has stronger assurance level than the minimum required.
                    int assuranceLevelAsInt;
                    int minimumAssuranceLevelAsInt;
                    if (!int.TryParse(assuranceLevel, out assuranceLevelAsInt) ||
                        !int.TryParse(minimumAssuranceLevel, out minimumAssuranceLevelAsInt) ||
                        assuranceLevelAsInt < minimumAssuranceLevelAsInt)
                    {
                        string errorMessage = string.Format(Resources.AssuranceLevelTooLow, assuranceLevel,
                                                            minimumAssuranceLevel);
                        AuditLogging.logEntry(Direction.IN, Operation.AUTHNREQUEST_POST,
                                              errorMessage + " Assertion: " + elem.OuterXml);

                        HandleError(context,
                                    string.Format(Resources.AssuranceLevelTooLow, assuranceLevel, minimumAssuranceLevel));
                        return;
                    }
                }
            }

            CheckConditions(context, assertion);
            AuditLogging.AssertionId = assertion.Id;
            AuditLogging.logEntry(Direction.IN, Operation.AUTHNREQUEST_POST,
                                  "Assertion validated succesfully");

            DoLogin(context, assertion);
        }
Пример #25
0
        /// <summary>
        /// Validates the Assertion's conditions
        /// Audience restrictions processing rules are:
        ///  - Within a single audience restriction condition in the assertion, the service must be configured
        ///    with an audience-list that contains at least one of the restrictions in the assertion ("OR" filter)
        ///  - When multiple audience restrictions are present within the same assertion, all individual audience
        ///    restriction conditions must be met ("AND" filter)
        /// </summary>
        private void ValidateConditions(Assertion assertion)
        {
            // Conditions are not required
            if (assertion.Conditions == null)
            {
                return;
            }

            bool oneTimeUseSeen        = false;
            bool proxyRestrictionsSeen = false;

            ValidateConditionsInterval(assertion.Conditions);

            foreach (ConditionAbstract cat in assertion.Conditions.Items)
            {
                if (cat is OneTimeUse)
                {
                    if (oneTimeUseSeen)
                    {
                        throw new Saml20FormatException("Assertion contained more than one condition of type OneTimeUse");
                    }
                    oneTimeUseSeen = true;
                    continue;
                }

                if (cat is ProxyRestriction)
                {
                    if (proxyRestrictionsSeen)
                    {
                        throw new Saml20FormatException("Assertion contained more than one condition of type ProxyRestriction");
                    }
                    proxyRestrictionsSeen = true;

                    ProxyRestriction proxyRestriction = (ProxyRestriction)cat;
                    if (!String.IsNullOrEmpty(proxyRestriction.Count))
                    {
                        uint res;
                        if (!UInt32.TryParse(proxyRestriction.Count, out res))
                        {
                            throw new Saml20FormatException("Count attribute of ProxyRestriction MUST BE a non-negative integer");
                        }
                    }

                    if (proxyRestriction.Audience != null)
                    {
                        foreach (string audience in proxyRestriction.Audience)
                        {
                            if (!Uri.IsWellFormedUriString(audience, UriKind.Absolute))
                            {
                                throw new Saml20FormatException("ProxyRestriction Audience MUST BE a wellformed uri");
                            }
                        }
                    }
                }

                // AudienceRestriction processing goes here (section 2.5.1.4 of [SAML2.0std])
                if (cat is AudienceRestriction)
                {
                    // No audience restrictions? No problems...
                    AudienceRestriction audienceRestriction = (AudienceRestriction)cat;
                    if (audienceRestriction.Audience == null || audienceRestriction.Audience.Count == 0)
                    {
                        continue;
                    }

                    // If there are no allowed audience uris configured for the service, the assertion is not
                    // valid for this service
                    if (_allowedAudienceUris == null || _allowedAudienceUris.Count < 1)
                    {
                        throw new Saml20FormatException("The service is not configured to meet any audience restrictions");
                    }

                    string match = null;
                    foreach (string audience in audienceRestriction.Audience)
                    {
                        //In QuirksMode this validation is omitted
                        if (!_quirksMode)
                        {
                            // The given audience value MUST BE a valid URI
                            if (!Uri.IsWellFormedUriString(audience, UriKind.Absolute))
                            {
                                throw new Saml20FormatException("Audience element has value which is not a wellformed absolute uri");
                            }
                        }

                        match =
                            _allowedAudienceUris.Find(
                                delegate(string allowedUri) { return(allowedUri.Equals(audience)); });
                        if (match != null)
                        {
                            break;
                        }
                    }

                    if (Trace.ShouldTrace(TraceEventType.Verbose))
                    {
                        string intended = "Intended uris: " + Environment.NewLine + String.Join(Environment.NewLine, audienceRestriction.Audience.ToArray());
                        string allowed  = "Allowed uris: " + Environment.NewLine + String.Join(Environment.NewLine, _allowedAudienceUris.ToArray());
                        Trace.TraceData(TraceEventType.Verbose, Trace.CreateTraceString(GetType(), "ValidateConditions"), intended, allowed);
                    }

                    if (match == null)
                    {
                        throw new Saml20FormatException("The service is not configured to meet the given audience restrictions");
                    }
                }
            }
        }
Пример #26
0
        private void TransferClient(IDPEndPoint idpEndpoint, Saml20AuthnRequest request, HttpContext context)
        {
            AuditLogging.AssertionId = request.ID;
            AuditLogging.IdpId       = idpEndpoint.Id;

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            IDPEndPointElement destination =
                DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idpEndpoint.SSOEndpoint, idpEndpoint.metadata.SSOEndpoints());



            request.Destination = destination.Url;

            bool   isPassive;
            string isPassiveAsString = context.Request.Params[IDPIsPassive];

            if (bool.TryParse(isPassiveAsString, out isPassive))
            {
                request.IsPassive = isPassive;
            }

            if (idpEndpoint.IsPassive)
            {
                request.IsPassive = true;
            }

            bool   forceAuthn;
            string forceAuthnAsString = context.Request.Params[IDPForceAuthn];

            if (bool.TryParse(forceAuthnAsString, out forceAuthn))
            {
                request.ForceAuthn = forceAuthn;
            }

            if (idpEndpoint.ForceAuthn)
            {
                request.ForceAuthn = true;
            }

            if (idpEndpoint.SSOEndpoint != null)
            {
                if (!string.IsNullOrEmpty(idpEndpoint.SSOEndpoint.ForceProtocolBinding))
                {
                    request.ProtocolBinding = idpEndpoint.SSOEndpoint.ForceProtocolBinding;
                }
            }

            //Save request message id to session
            SessionFactory.SessionContext.Current[SessionConstants.ExpectedInResponseTo] = request.ID;

            //Save request message id to session
            context.Session.Add(ExpectedInResponseToSessionKey, request.ID);

            if (destination.Binding == SAMLBinding.REDIRECT)
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Redirect, idpEndpoint.Id));

                HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder();
                builder.signingKey = _certificate.PrivateKey;
                builder.Request    = request.GetXml().OuterXml;
                string s = request.Destination + "?" + builder.ToQuery();

                AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT, "Redirecting user to IdP for authentication", builder.Request);

                context.Response.Redirect(s, true);
                return;
            }

            if (destination.Binding == SAMLBinding.POST)
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Post, idpEndpoint.Id));

                HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination);
                //Honor the ForceProtocolBinding and only set this if it's not already set
                if (string.IsNullOrEmpty(request.ProtocolBinding))
                {
                    request.ProtocolBinding = Saml20Constants.ProtocolBindings.HTTP_Post;
                }
                XmlDocument req = request.GetXml();
                XmlSignatureUtils.SignDocument(req, request.ID);
                builder.Request = req.OuterXml;
                AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_POST);

                builder.GetPage().ProcessRequest(context);
                return;
            }

            if (destination.Binding == SAMLBinding.ARTIFACT)
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Artifact, idpEndpoint.Id));

                HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context);
                //Honor the ForceProtocolBinding and only set this if it's not already set
                if (string.IsNullOrEmpty(request.ProtocolBinding))
                {
                    request.ProtocolBinding = Saml20Constants.ProtocolBindings.HTTP_Artifact;
                }
                AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT_ARTIFACT);

                builder.RedirectFromLogin(destination, request);
            }

            HandleError(context, Resources.BindingError);
        }
Пример #27
0
        /// <summary>
        /// Handles the selection of an IDP. If only one IDP is found, the user is automatically redirected to it.
        /// If several are found, and nothing indicates to which one the user should be sent, this method returns null.
        /// </summary>
        public IDPEndPoint RetrieveIDP(HttpContext context)
        {
            SAML20FederationConfig config = SAML20FederationConfig.GetConfig();

            //If idpChoice is set, use it value
            if (!string.IsNullOrEmpty(context.Request.Params[IDPChoiceParameterName]))
            {
                AuditLogging.logEntry(Direction.IN, Operation.DISCOVER,
                                      "Using IDPChoiceParamater: " + context.Request.Params[IDPChoiceParameterName]);
                IDPEndPoint endPoint = config.FindEndPoint(context.Request.Params[IDPChoiceParameterName]);
                if (endPoint != null)
                {
                    return(endPoint);
                }
            }

            //If we have a common domain cookie, use it's value
            //It must have been returned from the local common domain cookie reader endpoint.
            if (!string.IsNullOrEmpty(context.Request.QueryString["_saml_idp"]))
            {
                CommonDomainCookie cdc = new CommonDomainCookie(context.Request.QueryString["_saml_idp"]);
                if (cdc.IsSet)
                {
                    IDPEndPoint endPoint = config.FindEndPoint(cdc.PreferredIDP);
                    if (endPoint != null)
                    {
                        if (Trace.ShouldTrace(TraceEventType.Information))
                        {
                            Trace.TraceData(TraceEventType.Information, "IDP read from Common Domain Cookie: " + cdc.PreferredIDP);
                        }

                        return(endPoint);
                    }

                    AuditLogging.logEntry(Direction.IN, Operation.DISCOVER, "Invalid IdP in Common Domain Cookie, IdP not found in list of IdPs: " + cdc.PreferredIDP);
                }
            }

            //If there is only one configured IDPEndPoint lets just use that
            if (config.IDPEndPoints.Count == 1 && config.IDPEndPoints[0].metadata != null)
            {
                AuditLogging.logEntry(Direction.IN, Operation.DISCOVER, "No IdP selected in Common Domain Cookie, using default IdP: " + config.IDPEndPoints[0].Name);
                return(config.IDPEndPoints[0]);
            }

            // If one of the endpoints are marked with default, use that one
            var defaultIdp = config.Endpoints.IDPEndPoints.Find(idp => idp.Default);

            if (defaultIdp != null)
            {
                if (Trace.ShouldTrace(TraceEventType.Information))
                {
                    Trace.TraceData(TraceEventType.Information, "Using IdP marked as default: " + defaultIdp.Id);
                }

                return(defaultIdp);
            }

            // In case an Idp selection url has been configured, redirect to that one.
            if (!string.IsNullOrEmpty(config.Endpoints.idpSelectionUrl))
            {
                if (Trace.ShouldTrace(TraceEventType.Information))
                {
                    Trace.TraceData(TraceEventType.Information, "Redirecting to idpSelectionUrl for selection of IDP: " + config.Endpoints.idpSelectionUrl);
                }

                context.Response.Redirect(config.Endpoints.idpSelectionUrl);
            }

            // If an IDPSelectionEvent handler is present, request the handler for an IDP endpoint to use.
            var idpEndpoint = IDPSelectionUtil.InvokeIDPSelectionEventHandler(config.Endpoints);

            if (idpEndpoint != null)
            {
                return(idpEndpoint);
            }

            return(null);
        }