public void TestIntegrity_02()
 {
     HttpRedirectBindingBuilder binding = new HttpRedirectBindingBuilder();
     binding.Response = "Response";
     try
     {
         binding.Request = "Request";
         Assert.Fail("HttpRedirectBinding did not throw an exception when both Request and Response were set.");
     } catch(ArgumentException) { }
 }
예제 #2
0
        /// <summary>
        /// Transfers the message to the given endpoint using the HTTP-Redirect binding.
        /// </summary>
        protected static void HTTPRedirect(SAMLAction action, IDPEndPointElement endpoint, XmlNode message)
        {
            if (message.FirstChild is XmlDeclaration)
                message.RemoveChild(message.FirstChild);

            HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder();

            if (action == SAMLAction.SAMLRequest)
                builder.Request = message.OuterXml;
            else
                builder.Response = message.OuterXml;

            builder.signingKey = IDPConfig.IDPCertificate.PrivateKey;

            UriBuilder url = new UriBuilder(endpoint.Url);
            url.Query = builder.ToQuery();

            HttpContext.Current.Response.Redirect(url.ToString(), true);                        
        }
        public void TestDSASigning()
        {
            HttpRedirectBindingBuilder binding = new HttpRedirectBindingBuilder();

            DSACryptoServiceProvider key = new DSACryptoServiceProvider();
            binding.signingKey = key;
            binding.Request = string.Empty.PadLeft(500, 'a');

            // Now, parse the query.
            Uri url = new Uri("http://localhost/?" + binding.ToQuery());
            HttpRedirectBindingParser parser = new HttpRedirectBindingParser(url);
            Assert.That(parser.IsSigned);
            Assert.That(parser.IsRequest);
            Assert.That(parser.CheckSignature(key));

            // Create a new key set, and check that it can not verify the signature.
            DSACryptoServiceProvider evilKey = new DSACryptoServiceProvider();
            Assert.IsFalse(parser.CheckSignature(evilKey));
        }
예제 #4
0
		/// <summary>
		/// Initializes a new instance of the <see cref="Symplified.Auth.Saml20Authenticator"/> class.
		/// </summary>
		/// <param name="spName">Service Provider name.</param>
		/// <param name="idpMetadata">Identity Provider metadata.</param>
		public Saml20Authenticator (string spName, Saml20MetadataDocument idpMetadata) :
			base (PLACEHOLDER_URI, PLACEHOLDER_URI)
		{
			_spName = (string.IsNullOrEmpty (spName)) ? "symplified-mobile-sp" : spName;
			_idpMetadata = idpMetadata;

			var url = _idpMetadata.SSOEndpoint (SAMLBinding.POST).Url;
			var separator = url.Contains ("?") ? "&" : "?";

			var authnRequest = Saml20AuthnRequest.GetDefault (_spName);

			var builder = new HttpRedirectBindingBuilder ();
			builder.Request = authnRequest.GetXml ().OuterXml;

			initialUrl = new Uri (
				String.Format (
					"{0}{1}{2}", url, separator, builder.ToQuery()
				)
			);
		}
        private void TransferClient(IDPEndPoint idpEndpoint, Saml20AuthnRequest request, HttpContext context)
        {
            AuditLogging.AssertionId = request.ID;
            AuditLogging.IdpId = idpEndpoint.Id;

            //Set the last IDP we attempted to login at.
            context.Session[IDPTempSessionKey]= 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;

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

            object isPassiveFlag = context.Session[IDPIsPassive];

            if (isPassiveFlag != null && (bool)isPassiveFlag)
            {
                request.IsPassive = true;
                context.Session[IDPIsPassive] = null;
            }

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

            object forceAuthnFlag = context.Session[IDPForceAuthn];

            if (forceAuthnFlag != null && (bool)forceAuthnFlag)
            {
                request.ForceAuthn = true;
                context.Session[IDPForceAuthn] = null;
            }

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

            //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);
        }
        public void TestRelaystate_02()
        {
            HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder();
            bindingBuilder.Response = "A random response... !!!! .... ";
            string relaystate = string.Empty.PadRight(10, 'A');
            bindingBuilder.RelayState = relaystate;

            // When using the builder to create a response, the relaystate 
            // should not be encoded, and can thus be located in the query-string
            string query = bindingBuilder.ToQuery();
            Assert.That(query.Contains(relaystate));
        }
        public void TestRelaystate_01()
        {
            HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder();
            bindingBuilder.Request = "A random request... !!!! .... ";
            string relaystate = string.Empty.PadRight(10, 'A');
            bindingBuilder.RelayState = relaystate;

            // When using the builder to create a request, the relaystate should be encoded.
            string query = bindingBuilder.ToQuery();
            Assert.That(!query.Contains(relaystate));            
        }
        public void TestParsing_02()
        {
            HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder();
            string request = string.Empty.PadRight(140, 'l');
            string relaystate = "A relaystate test. @@@!!!&&&///";

            bindingBuilder.Request = request;
            bindingBuilder.RelayState = relaystate;

            string query = bindingBuilder.ToQuery();
            NameValueCollection coll = QueryToNameValueCollection(query);
            Assert.AreEqual(2, coll.Count);

            Uri url = new Uri("http://localhost/?" + query);
            HttpRedirectBindingParser bindingParser = new HttpRedirectBindingParser(url);
            Assert.IsTrue(bindingParser.IsRequest);
            Assert.IsFalse(bindingParser.IsResponse);
            Assert.IsFalse(bindingParser.IsSigned);
            Assert.IsNotNull(bindingParser.RelayState );
            Assert.AreEqual(relaystate, bindingParser.RelayStateDecoded);
            Assert.AreEqual(request, bindingParser.Message);
        }
        public void TestParsing_01()
        {
            HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder();
            string request = string.Empty.PadLeft(350, 'A');
            bindingBuilder.Request = request;

            string query = bindingBuilder.ToQuery();
            NameValueCollection coll = QueryToNameValueCollection(query);
            Assert.That(coll.Count == 1);            

            Uri url = new Uri("http://localhost/?" + query);
            HttpRedirectBindingParser bindingParser = new HttpRedirectBindingParser(url);
            Assert.That(bindingParser.IsRequest);
            Assert.That(!bindingParser.IsResponse);
            Assert.That(!bindingParser.IsSigned);
            Assert.AreEqual(request, bindingParser.Message);

            try
            {
                bindingParser.CheckSignature(new RSACryptoServiceProvider());
                Assert.Fail("Trying to verify signature of an unsigned request should have thrown an exception.");
            } catch(InvalidOperationException) {}
        }
        private void HandleRequest(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "HandleRequest()");

            //Fetch the endpoint configuration
            IDPEndPoint idpEndpoint = RetrieveIDPConfiguration(context.Session[IDPLoginSessionKey].ToString());

            IDPEndPointElement destination =
                DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idpEndpoint.SLOEndpoint, idpEndpoint.metadata.SLOEndpoints());

            //Fetch config object
            SAML20FederationConfig config = ConfigurationReader.GetConfig<SAML20FederationConfig>();
                        
            //Build the response object
            Saml20LogoutResponse response = new Saml20LogoutResponse();
            response.Issuer = config.ServiceProvider.ID;
            response.Destination = destination.Url;
            response.StatusCode = Saml20Constants.StatusCodes.Success;

            string message = string.Empty;

            if(context.Request.RequestType == "GET") // HTTP Redirect binding
            {
                HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url);
                IDPEndPoint endpoint = config.FindEndPoint(idpEndpoint.Id);

                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP");
                    HandleError(context, "Cannot find metadata for IdP " + idpEndpoint.Id);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Invalid signature redirect-binding, msg: " + parser.Message);
                    HandleError(context, Resources.SignatureInvalid);
                    return;
                }

                message = parser.Message;
            }
            else if (context.Request.RequestType == "POST") // HTTP Post binding
            {
                HttpPostBindingParser parser = new HttpPostBindingParser(context);

                if (!parser.IsSigned())
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message);
                    HandleError(context, Resources.SignatureNotPresent);
                }

                IDPEndPoint endpoint = config.FindEndPoint(idpEndpoint.Id);
                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP");
                    HandleError(context, "Cannot find metadata for IdP " + idpEndpoint.Id);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                // handle a logout-request
                if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Invalid signature post-binding, msg: " + parser.Message);
                    HandleError(context, Resources.SignatureInvalid);
                }

                message = parser.Message;
            }else
            {
                //Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS
                HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType));
            }

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

            //Log the user out locally
            DoLogout(context, true);

            LogoutRequest req = Serialization.DeserializeFromXmlString<LogoutRequest>(message);

            response.InResponseTo = req.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 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;

            string nameIdFormat = context.Session[IDPNameIdFormat].ToString();
            request.SubjectToLogOut.Format = nameIdFormat;
            
            if (destination.Binding == SAMLBinding.POST)
            {
                HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination);
                request.Destination = destination.Url;
                request.Reason = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = context.User.Identity.Name;
                request.SessionIndex = context.Session[IDPSessionIdKey].ToString();
                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 = context.User.Identity.Name;
                request.SessionIndex = context.Session[IDPSessionIdKey].ToString();
                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 = context.User.Identity.Name;
                request.SessionIndex = context.Session[IDPSessionIdKey].ToString();

                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);
        }