Пример #1
0
        private void ReadMetadataIdpDescriptor(EntityDescriptor metadata)
        {
            var idpDescriptor = metadata.RoleDescriptors
                                .OfType <IdpSsoDescriptor>().Single();

            WantAuthnRequestsSigned = idpDescriptor.WantAuthnRequestsSigned ?? false;

            var ssoService = GetPreferredEndpoint(idpDescriptor.SingleSignOnServices);

            if (ssoService != null)
            {
                binding = Saml2Binding.UriToSaml2BindingType(ssoService.Binding);
                singleSignOnServiceUrl = ssoService.Location;
            }

            var sloService = GetPreferredEndpoint(idpDescriptor.SingleLogoutServices);

            if (sloService != null)
            {
                SingleLogoutServiceUrl         = sloService.Location;
                SingleLogoutServiceBinding     = Saml2Binding.UriToSaml2BindingType(sloService.Binding);
                singleLogoutServiceResponseUrl = sloService.ResponseLocation;
            }

            foreach (var kv in idpDescriptor.ArtifactResolutionServices)
            {
                var ars = kv.Value;
                artifactResolutionServiceUrls[ars.Index] = ars.Location;
            }

            var arsKeys = idpDescriptor.ArtifactResolutionServices.ToLookup(x => x.Value.Index);

            foreach (var ars in artifactResolutionServiceUrls.Keys
                     .Where(k => !arsKeys.Contains(k)))
            {
                artifactResolutionServiceUrls.Remove(ars);
            }

            var keys = idpDescriptor.Keys.Where(k => k.Use == KeyType.Unspecified || k.Use == KeyType.Signing);

            signingKeys.SetLoadedItems(keys.Select(k => k.KeyInfo
                                                   .MakeSecurityKeyIdentifier().First(c => c.CanCreateKey)).ToList());
        }
        public void LogoutCommand_Run_ThrowsOnUnknownMessageRecevied()
        {
            var msg = new Saml2MessageImplementation
            {
                MessageName        = "SAMLRequest",
                SigningCertificate = SignedXmlHelper.TestCert,
                DestinationUrl     = new Uri("http://localhost"),
                XmlData            = $"<Unknown><Issuer xmlns=\"{Saml2Namespaces.Saml2Name}\">https://idp.example.com</Issuer></Unknown>"
            };

            var url = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                      .Bind(msg).Location;

            var request = new HttpRequestData("GET", url);

            CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
            .Invoking(c => c.Run(request, StubFactory.CreateOptions()))
            .ShouldThrow <NotImplementedException>();
        }
Пример #3
0
        private static string GetRedirectUri(Saml2Binding binding, Saml2AuthenticationOptions options)
        {
            var relayState = binding.GetRelayStateQuery();

            if (relayState.ContainsKey(_relayStateRedirectUri))
            {
                var redirectUri = relayState[_relayStateRedirectUri];
                return(redirectUri);
            }

            if (relayState.ContainsKey(_relayStateReturnUrl))
            {
                var returnUrl   = relayState[_relayStateReturnUrl];
                var redirectUri = options.ExternalLoginCallbackPath.Add(new QueryString(_relayStateReturnUrl, returnUrl));
                return(redirectUri);
            }

            return(options.ExternalLoginCallbackPath.Value);
        }
Пример #4
0
        public void Saml2RedirectBinding_Bind()
        {
            var message = new Saml2MessageImplementation
            {
                XmlData        = ExampleXmlData,
                DestinationUrl = new Uri("http://www.example.com/sso"),
                MessageName    = "SAMLRequest"
            };

            var result = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(message);

            var expected = new CommandResult()
            {
                Location       = new Uri("http://www.example.com/sso?SAMLRequest=" + ExampleSerializedData),
                HttpStatusCode = System.Net.HttpStatusCode.SeeOther,
            };

            CompareCommandResults(result, expected);
        }
Пример #5
0
        public async Task KentorAuthServicesAuthenticationMiddleware_HandlesLogoutResponse()
        {
            var app     = CreateAppBuilder();
            var options = new KentorAuthServicesAuthenticationOptions(true);
            var subject = new KentorAuthServicesAuthenticationMiddleware(
                null,
                app,
                options);

            var context = OwinTestHelpers.CreateOwinContext();

            var relayState = "MyRelayState";
            var response   = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = new Uri("https://sp.example.com/AuthServices/Logout"),
                RelayState         = relayState,
                SigningCertificate = SignedXmlHelper.TestCert,
                Issuer             = new EntityId("https://idp.example.com")
            };
            var requestUri = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(response).Location;

            var cookieData = HttpRequestData.EscapeBase64CookieValue(
                Convert.ToBase64String(
                    options.DataProtector.Protect(
                        Encoding.UTF8.GetBytes("http://loggedout.example.com/"))));

            context.Request.Headers["Cookie"] = $"Kentor.{relayState}={cookieData}";
            context.Request.Path        = new PathString(requestUri.AbsolutePath);
            context.Request.QueryString = new QueryString(requestUri.Query.TrimStart('?'));

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
            }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().Be("http://loggedout.example.com/");
        }
Пример #6
0
        public ActionResult Index(Guid?idpId)
        {
            var model = new HomePageModel
            {
                AssertionModel = AssertionModel.CreateFromConfiguration(),
            };

            if (idpId.HasValue)
            {
                var fileData = GetCachedConfiguration(idpId.Value);
                if (fileData != null)
                {
                    if (!string.IsNullOrEmpty(fileData.DefaultAssertionConsumerServiceUrl))
                    {
                        // Override default StubIdp Acs with Acs from IdpConfiguration
                        model.AssertionModel.AssertionConsumerServiceUrl = fileData.DefaultAssertionConsumerServiceUrl;
                    }
                    model.CustomDescription     = fileData.IdpDescription;
                    model.AssertionModel.NameId = null;
                    model.HideDetails           = fileData.HideDetails;
                }
            }

            var requestData = Request.ToHttpRequestData();

            if (requestData.QueryString["SAMLRequest"].Any())
            {
                var extractedMessage = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                                       .Unbind(requestData, null);

                var request = new Saml2AuthenticationRequest(
                    extractedMessage.Data,
                    extractedMessage.RelayState);

                model.AssertionModel.InResponseTo = request.Id.Value;
                model.AssertionModel.AssertionConsumerServiceUrl = request.AssertionConsumerServiceUrl.ToString();
                model.AssertionModel.RelayState      = extractedMessage.RelayState;
                model.AssertionModel.AuthnRequestXml = extractedMessage.Data.OuterXml;
            }

            return(View(model));
        }
Пример #7
0
        public void Saml2PostBinding_Bind()
        {
            var message = new Saml2MessageImplementation
            {
                XmlData        = "<root><content>data</content></root>",
                DestinationUrl = new Uri("http://www.example.com/acs"),
                MessageName    = "SAMLMessageName"
            };

            var result = Saml2Binding.Get(Saml2BindingType.HttpPost).Bind(message);

            var expected = new CommandResult()
            {
                ContentType = "text/html",
                Content     = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.1//EN""
""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"">
<html xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"">
<body onload=""document.forms[0].submit()"">
<noscript>
<p>
<strong>Note:</strong> Since your browser does not support JavaScript, 
you must press the Continue button once to proceed.
</p>
</noscript>
<form action=""http://www.example.com/acs"" method=""post"">
<div>
<input type=""hidden"" name=""SAMLMessageName""
value=""PHJvb3Q+PGNvbnRlbnQ+ZGF0YTwvY29udGVudD48L3Jvb3Q+""/>
</div>
<noscript>
<div>
<input type=""submit"" value=""Continue""/>
</div>
</noscript>
</form>
</body>
</html>"
            };

            result.ShouldBeEquivalentTo(expected);
        }
Пример #8
0
        public void Saml2RedirectBinding_Bind_WithXmlDeclaration()
        {
            var message = new Saml2MessageImplementation
            {
                XmlData        = "<xml/>",
                DestinationUrl = new Uri("http://www.example.com/sso"),
                MessageName    = "SAMLRequest"
            };

            var result = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(message, null, (m, x, t) =>
            {
                x.Declaration = new XDeclaration("42.17", "utf-73", null);
            });

            var payload = Uri.UnescapeDataString(result.Location.Query.Split('=')[1]);

            var inflated = InflateBase64EncodedData(payload);

            inflated.Should().Be("<?xml version=\"42.17\" encoding=\"utf-73\"?>\r\n<xml />");
        }
Пример #9
0
        public ActionResult RespondToLogoutRequest()
        {
            var requestData  = Request.ToHttpRequestData(true);
            var binding      = Saml2Binding.Get(requestData);
            var unbindResult = binding.Unbind(requestData, null);

            var logoutRequest = Saml2LogoutRequest.FromXml(unbindResult.Data);

            var model = new RespondToLogoutRequestModel()
            {
                LogoutRequestXml = unbindResult.Data.PrettyPrint(),
                InResponseTo     = logoutRequest.Id.Value,
                DestinationUrl   = new Uri(new Uri(logoutRequest.Issuer.Id + "/"), "Logout"),
                RelayState       = Request.QueryString["RelayState"]
            };

            return(Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                   .Bind(model.ToLogoutResponse())
                   .ToActionResult());
        }
Пример #10
0
        public ActionResult Index()
        {
            var model = AssertionModel.CreateFromConfiguration();

            var requestData = Request.ToHttpRequestData();

            if (requestData.QueryString["SAMLRequest"].Any())
            {
                var decodedXmlData = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                                     .Unbind(requestData);

                var request = Saml2AuthenticationRequest.Read(decodedXmlData);

                model.InResponseTo = request.Id;
                model.AssertionConsumerServiceUrl = request.AssertionConsumerServiceUrl.ToString();
                model.AuthnRequestXml             = decodedXmlData;
            }

            return(View(model));
        }
Пример #11
0
        public void LogoutCommand_Run_ThrowsOnMissingIssuerInReceivedMessage()
        {
            var msg = new Saml2MessageImplementation
            {
                MessageName        = "SAMLRequest",
                SigningCertificate = SignedXmlHelper.TestCert,
                DestinationUrl     = new Uri("http://localhost"),
                XmlData            = "<Xml />"
            };

            var url = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                      .Bind(msg).Location;

            var request = new HttpRequestData("GET", url);

            CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
            .Invoking(c => c.Run(request, StubFactory.CreateOptions()))
            .Should().Throw <InvalidSignatureException>()
            .WithMessage("There is no Issuer element in the message, so there is no way to know what certificate to use to validate the signature.");
        }
        public void Saml2RedirectBinding_Bind_WithQueryIn_destinationUrl()
        {
            var message = new Saml2MessageImplementation
            {
                XmlData        = ExampleXmlData,
                DestinationUrl = new Uri("http://www.example.com/acs?aQueryParam=QueryParamValue"),
                MessageName    = "SAMLRequest"
            };

            var result = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(message);

            var expected = new CommandResult()
            {
                Location = new Uri("http://www.example.com/acs?aQueryParam=QueryParamValue&SAMLRequest="
                                   + ExampleSerializedData),
                HttpStatusCode = System.Net.HttpStatusCode.SeeOther,
            };

            result.ShouldBeEquivalentTo(expected);
        }
Пример #13
0
        private async Task <IActionResult> AuthnRequestAsync <T>(SamlUpParty party, Saml2Binding <T> binding, SamlUpSequenceData samlUpSequenceData)
        {
            var samlConfig = saml2ConfigurationLogic.GetSamlUpConfig(party);

            binding.RelayState = SequenceString;
            var saml2AuthnRequest = new Saml2AuthnRequest(samlConfig);

            switch (samlUpSequenceData.LoginAction)
            {
            case LoginAction.ReadSession:
                saml2AuthnRequest.IsPassive = true;
                break;

            case LoginAction.RequireLogin:
                saml2AuthnRequest.ForceAuthn = true;
                break;

            default:
                break;
            }

            binding.Bind(saml2AuthnRequest);
            logger.ScopeTrace($"SAML Authn request '{saml2AuthnRequest.XmlDocument.OuterXml}'.");
            logger.ScopeTrace($"Authn URL '{samlConfig.SingleSignOnDestination?.OriginalString}'.");
            logger.ScopeTrace("Up, Sending SAML Authn request.", triggerEvent: true);

            securityHeaderLogic.AddFormActionAllowAll();

            if (binding is Saml2Binding <Saml2RedirectBinding> )
            {
                return(await(binding as Saml2RedirectBinding).ToActionFormResultAsync());
            }
            else if (binding is Saml2Binding <Saml2PostBinding> )
            {
                return(await(binding as Saml2PostBinding).ToActionFormResultAsync());
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Пример #14
0
        public void Saml2RedirectBinding_Bind_With_RelayState()
        {
            var message = new Saml2MessageImplementation
            {
                XmlData        = "Data",
                RelayState     = "SomeState that needs escaping #%=3",
                DestinationUrl = new Uri("http://host"),
                MessageName    = "SAMLRequest"
            };

            var expected = new CommandResult()
            {
                Location = new Uri("http://host?SAMLRequest=c0ksSQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%3D%3D"
                                   + "&RelayState=" + Uri.EscapeDataString(message.RelayState)),
                HttpStatusCode = System.Net.HttpStatusCode.SeeOther
            };

            var result = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(message);

            CompareCommandResults(result, expected);
        }
Пример #15
0
        public void Saml2PostBinding_Unbind_Request()
        {
            var requestData = Convert.ToBase64String(Encoding.UTF8.GetBytes("<data/>"));

            var request = new HttpRequestData(
                "POST",
                new Uri("http://something"),
                "/path",
                new KeyValuePair <string, string[]>[]
            {
                new KeyValuePair <string, string[]>("SAMLRequest", new[] { requestData })
            },
                null,
                null);

            var actual = Saml2Binding.Get(request).Unbind(request, StubFactory.CreateOptions());

            actual.Data.Should().BeEquivalentTo(XmlHelpers.XmlDocumentFromString("<data/>").DocumentElement);
            actual.RelayState.Should().BeNull();
            actual.TrustLevel.Should().Be(TrustLevel.None);
        }
Пример #16
0
        public void Saml2ArtifactBinding_Unbind_FromGetUsesIdpFromNotification()
        {
            var issuer   = new EntityId("https://idp.example.com");
            var artifact = Uri.EscapeDataString(
                Convert.ToBase64String(
                    Saml2ArtifactBinding.CreateArtifact(issuer, 0x1234)));

            var relayState = "relayState";

            var relayData = new Dictionary <string, string>
            {
                { "key", "value" }
            };

            var r = new HttpRequestData(
                "GET",
                new Uri($"http://example.com/path/acs?SAMLart={artifact}&RelayState={relayState}"),
                null,
                null,
                new StoredRequestState(issuer, null, null, relayData));

            var options = StubFactory.CreateOptions();

            var idp = options.IdentityProviders.Default;

            options.IdentityProviders.Remove(idp.EntityId);

            var getIdentityProviderCalled = false;

            options.Notifications.GetIdentityProvider = (ei, rd, opt) =>
            {
                getIdentityProviderCalled = true;
                rd["key"].Should().Be("value");
                return(idp);
            };

            var result = Saml2Binding.Get(Saml2BindingType.Artifact).Unbind(r, options);

            getIdentityProviderCalled.Should().BeTrue();
        }
Пример #17
0
        public ActionResult Index(Guid?idpId)
        {
            var requestData = Request.ToHttpRequestData();

            if (requestData.QueryString["SAMLRequest"].Any())
            {
                var decodedXmlData = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                                     .Unbind(requestData);

                var request = Saml2AuthenticationRequest.Read(decodedXmlData);

                var model = new AssertionModel();

                model.InResponseTo = request.Id;
                model.AssertionConsumerServiceUrl = request.AssertionConsumerServiceUrl.ToString();
                model.AuthnRequestXml             = decodedXmlData;
                model.NameId = ((ClaimsIdentity)User.Identity).Name;

                var manager = SessionManager.Instance;


                var response = model.ToSaml2Response();

                manager.AddSession(model.NameId, new Session()
                {
                    Id        = Guid.Parse(request.Id.Substring(2)),
                    Ip        = Request.UserHostAddress,
                    UserAgent = Request.UserAgent,
                    LogoutUrl = request.Issuer.Id,
                    Issuer    = response.Issuer.Id
                });

                var commandResult = Saml2Binding.Get(Saml2BindingType.HttpPost)
                                    .Bind(response);

                return(commandResult.ToActionResult());
            }

            throw new InvalidOperationException();
        }
        /// <summary>
        /// Get the Relay State Query string as a Dictionary of key value pairs.
        /// </summary>
        public static Dictionary <string, string> GetRelayStateQuery(this Saml2Binding saml2Binding)
        {
            Dictionary <string, string> elements = new Dictionary <string, string>();

            if (string.IsNullOrWhiteSpace(saml2Binding.RelayState))
            {
                return(elements);
            }

            var match = Regex.Match(saml2Binding.RelayState, @"(?<key>[^=^&]+)=(?<value>[^=^&]*)(&(?<key>[^=^&]+)=(?<value>[^=^&]*))*");

            if (!match.Success || match.Groups["key"] == null || match.Groups["value"] == null)
            {
                throw new InvalidDataException("Invalid Relay State Query.");
            }

            for (var i = 0; i < match.Groups["key"].Captures.Count; i++)
            {
                elements.Add(match.Groups["key"].Captures[i].Value, HttpUtility.UrlDecode(match.Groups["value"].Captures[i].Value));
            }
            return(elements);
        }
Пример #19
0
        public void Saml2ArtifactBinding_Unbind_FromGetWithoutRelayState()
        {
            var issuer   = new EntityId("https://idp.example.com");
            var artifact = Uri.EscapeDataString(
                Convert.ToBase64String(
                    Saml2ArtifactBinding.CreateArtifact(issuer, 0x1234)));

            var r = new HttpRequestData(
                "GET",
                new Uri($"http://example.com/path/acs?SAMLart={artifact}"));

            StubServer.LastArtifactResolutionSoapActionHeader = null;

            var result = Saml2Binding.Get(Saml2BindingType.Artifact).Unbind(r, StubFactory.CreateOptions());

            var xmlDocument = XmlHelpers.XmlDocumentFromString(
                "<message>   <child-node /> </message>");

            var expected = new UnbindResult(xmlDocument.DocumentElement, null, TrustLevel.None);

            result.Should().BeEquivalentTo(expected);
        }
Пример #20
0
        public void Saml2ArtifactBinding_Unbind_FromGet_SignsArtifactResolve()
        {
            var issuer   = new EntityId("https://idp.example.com");
            var artifact = Uri.EscapeDataString(
                Convert.ToBase64String(
                    Saml2ArtifactBinding.CreateArtifact(issuer, 0x1234)));

            var r = new HttpRequestData(
                "GET",
                new Uri($"http://example.com/path/acs?SAMLart={artifact}"));

            var options = StubFactory.CreateOptions();

            options.SPOptions.ServiceCertificates.Add(new ServiceCertificate
            {
                Certificate = SignedXmlHelper.TestCert
            });

            var result = Saml2Binding.Get(Saml2BindingType.Artifact).Unbind(r, options);

            StubServer.LastArtifactResolutionWasSigned.Should().BeTrue();
        }
        public void Saml2ArtifactBinding_Unbind_FromPost()
        {
            var issuer   = new EntityId("https://idp.example.com");
            var artifact = Convert.ToBase64String(
                Saml2ArtifactBinding.CreateArtifact(issuer, 0x1234));

            var relayState = MethodBase.GetCurrentMethod().Name;

            PrepareArtifactState(relayState, issuer);

            var r = new HttpRequestData(
                "POST",
                new Uri("http://example.com"),
                "/ModulePath",
                new KeyValuePair <string, string[]>[]
            {
                new KeyValuePair <string, string[]>("SAMLart", new[] { artifact }),
                new KeyValuePair <string, string[]>("RelayState", new[] { relayState })
            },
                null,
                null);

            StubServer.LastArtifactResolutionSoapActionHeader = null;

            var result = Saml2Binding.Get(Saml2BindingType.Artifact).Unbind(r, StubFactory.CreateOptions());

            var xmlDocument = new XmlDocument()
            {
                PreserveWhitespace = true
            };

            xmlDocument.LoadXml("<message>   <child-node /> </message>");

            var expected = new UnbindResult(xmlDocument.DocumentElement, relayState, TrustLevel.None);

            result.ShouldBeEquivalentTo(expected);
            StubServer.LastArtifactResolutionSoapActionHeader.Should().Be(
                "http://www.oasis-open.org/committees/security");
        }
Пример #22
0
        public XElement ToXElement()
        {
            var x = new XElement(Saml2Namespaces.Saml2P + LocalName);

            x.Add(base.ToXNodes());
            if (Binding.HasValue)
            {
                x.AddAttributeIfNotNullOrEmpty("ProtocolBinding", Saml2Binding.Saml2BindingTypeToUri(Binding.Value));
            }
            x.AddAttributeIfNotNullOrEmpty("AssertionConsumerServiceURL", AssertionConsumerServiceUrl);
            x.AddAttributeIfNotNullOrEmpty("AttributeConsumingServiceIndex", AttributeConsumingServiceIndex);
            if (ForceAuthentication)
            {
                x.Add(new XAttribute("ForceAuthn", ForceAuthentication));
            }

            if (Subject != null && Subject.NameId != null && !string.IsNullOrEmpty(Subject.NameId.Value))
            {
                x.Add(Subject.ToXElement());
            }

            AddNameIdPolicy(x);

            if (RequestedAuthnContext != null && RequestedAuthnContext.ClassRef != null)
            {
                x.Add(new XElement(Saml2Namespaces.Saml2P + "RequestedAuthnContext",
                                   new XAttribute("Comparison", RequestedAuthnContext.Comparison.ToString().ToLowerInvariant()),

                                   // Add the classref as original string to avoid URL normalization
                                   // and make sure the emitted value is exactly the configured.
                                   new XElement(Saml2Namespaces.Saml2 + "AuthnContextClassRef",
                                                RequestedAuthnContext.ClassRef.OriginalString)));
            }

            AddScoping(x);

            return(x);
        }
Пример #23
0
        public void LogoutCommand_Run_IncomingRequest_ThrowsOnNoConfiguredSigningCert()
        {
            var request = new Saml2LogoutRequest()
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/AuthServices/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                SigningCertificate = SignedXmlHelper.TestCert,
                NameId             = new Saml2NameIdentifier("NameId"),
                SessionIndex       = "SessionID"
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(request);

            var httpRequest = new HttpRequestData("GET", bindResult.Location);

            var options = StubFactory.CreateOptions();

            CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
            .Invoking(c => c.Run(httpRequest, options))
            .ShouldThrow <ConfigurationErrorsException>()
            .WithMessage("Received a LogoutRequest from \"https://idp.example.com\" but cannot reply because single logout responses must be signed and there is no signing certificate configured. Looks like the idp is configured for Single Logout despite AuthServices not exposing that functionality in the metadata.");
        }
        public ActionResult Index(Guid?idpId, HomePageModel model)
        {
            if (ModelState.IsValid)
            {
                var response = model.AssertionModel.ToSaml2Response();

                return(Saml2Binding.Get(model.AssertionModel.ResponseBinding)
                       .Bind(response).ToActionResult());
            }

            if (model.AssertionModel == null)
            {
                model.AssertionModel = AssertionModel.CreateFromConfiguration();
            }
            ;

            if (HandleReceivedAuthnReqest(model))
            {
                ReadCustomIdpConfig(idpId, model);
            }

            return(View(model));
        }
        public void LogoutCommand_Run_HandlesLogoutResponse()
        {
            var relayState = "MyRelayState";
            var response   = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/AuthServices/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                InResponseTo       = new Saml2Id(),
                SigningCertificate = SignedXmlHelper.TestCert,
                RelayState         = relayState
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var request = new HttpRequestData("GET",
                                              bindResult.Location,
                                              "http://sp-internal.example.com/path/AuthServices",
                                              null,
                                              new StoredRequestState(null, new Uri("http://loggedout.example.com"), null, null));

            var options = StubFactory.CreateOptions();

            options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/path/");

            var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
                         .Run(request, options);

            var expected = new CommandResult
            {
                Location        = new Uri("http://loggedout.example.com"),
                HttpStatusCode  = HttpStatusCode.SeeOther,
                ClearCookieName = "Kentor." + relayState
            };

            actual.ShouldBeEquivalentTo(expected);
        }
Пример #26
0
        public void LogoutCommand_Run_IncomingRequest_ThroughRedirectBinding_ThrowsOnMissingSignature()
        {
            var request = new Saml2LogoutRequest()
            {
                DestinationUrl = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer         = new EntityId("https://idp.example.com"),
                NameId         = new Saml2NameIdentifier("NameId"),
                SessionIndex   = "SessionID"
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(request);

            var httpRequest = new HttpRequestData("GET", bindResult.Location);

            var options = StubFactory.CreateOptions();

            options.SPOptions.ServiceCertificates.Add(SignedXmlHelper.TestCert);

            CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
            .Invoking(c => c.Run(httpRequest, options))
            .Should().Throw <UnsuccessfulSamlOperationException>()
            .WithMessage("Received a LogoutRequest from https://idp.example.com that cannot be processed because it is not signed.");
        }
Пример #27
0
        public async Task Saml2Handler_HandleRequestAsync_TerminatesLocalSessionOnLogoutRequest(string signOutScheme)
        {
            var context = new Saml2HandlerTestContext();

            context.Subject.options.IdentityProviders.Default.SingleLogoutServiceUrl = new Uri("https://idp.example.com/Logout");
            context.Subject.options.SPOptions.ServiceCertificates.Add(new X509Certificate2("Sustainsys.Saml2.Tests.pfx"));
            context.Subject.options.SignOutScheme = signOutScheme;

            var request = new Saml2LogoutRequest()
            {
                SessionIndex       = "SessionId",
                DestinationUrl     = new Uri("http://sp.example.com/Saml2/Logout"),
                NameId             = new Saml2NameIdentifier("NameId"),
                Issuer             = new EntityId("https://idp.example.com"),
                SigningCertificate = SignedXmlHelper.TestCert,
                SigningAlgorithm   = SecurityAlgorithms.RsaSha256Signature
            };

            var url = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                      .Bind(request).Location;

            context.HttpContext.Request.Path        = new PathString(url.AbsolutePath);
            context.HttpContext.Request.QueryString = new QueryString(url.Query);

            var authService = Substitute.For <IAuthenticationService>();

            context.HttpContext.RequestServices.GetService(typeof(IAuthenticationService))
            .Returns(authService);

            await context.Subject.HandleRequestAsync();

            await authService.Received().SignOutAsync(
                context.HttpContext,
                signOutScheme ?? TestHelpers.defaultSignInScheme,
                null);
        }
Пример #28
0
        public void Saml2ArtifactBinding_Unbind_FromGet_ArtifactIsntHashOfEntityId()
        {
            var issuer   = new EntityId("https://idp.example.com");
            var artifact = Uri.EscapeDataString(
                Convert.ToBase64String(
                    Saml2ArtifactBinding.CreateArtifact(
                        new EntityId("https://this.entityid.is.invalid"),
                        0x1234)));

            var relayState = "relayState";

            var r = new HttpRequestData(
                "GET",
                new Uri($"http://example.com/path/acs?SAMLart={artifact}&RelayState={relayState}"),
                null,
                null,
                new StoredRequestState(issuer, null, null, null));

            StubServer.LastArtifactResolutionSoapActionHeader = null;

            var result = Saml2Binding.Get(Saml2BindingType.Artifact).Unbind(r, StubFactory.CreateOptions());

            var xmlDocument = new XmlDocument()
            {
                PreserveWhitespace = true
            };

            xmlDocument.LoadXml("<message>   <child-node /> </message>");

            var expected = new UnbindResult(xmlDocument.DocumentElement, relayState, TrustLevel.None);

            result.ShouldBeEquivalentTo(expected);
            StubServer.LastArtifactResolutionSoapActionHeader.Should().Be(
                "http://www.oasis-open.org/committees/security");
            StubServer.LastArtifactResolutionWasSigned.Should().BeFalse();
        }
Пример #29
0
        public void Saml2RedirectBinding_Unbind()
        {
            // Example from http://en.wikipedia.org/wiki/SAML_2.0#HTTP_Redirect_Binding
            var xmlData = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
                          + "<samlp:AuthnRequest\r\n"
                          + "  xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"\r\n"
                          + "  xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"\r\n"
                          + "  ID=\"aaf23196-1773-2113-474a-fe114412ab72\"\r\n"
                          + "  Version=\"2.0\"\r\n"
                          + "  IssueInstant=\"2004-12-05T09:21:59Z\"\r\n"
                          + "  AssertionConsumerServiceIndex=\"0\"\r\n"
                          + "  AttributeConsumingServiceIndex=\"0\">\r\n"
                          + "  <saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>\r\n"
                          + "  <samlp:NameIDPolicy\r\n"
                          + "    AllowCreate=\"true\"\r\n"
                          + "    Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\"/>\r\n"
                          + "</samlp:AuthnRequest>\r\n";

            var serializedData = "fZFfa8IwFMXfBb9DyXvaJtZ1BqsURRC2Mabbw95ivc5Am3TJrXPffmmLY3%2fA15Pzuyf33On8XJXBCaxTRmeEhTEJQBdmr%2fRbRp63K3pL5rPhYOpkVdYib%2fCon%2bC9AYfDQRB4WDvRvWWksVoY6ZQTWlbgBBZik9%2ffCR7GorYGTWFK8pu6DknnwKL%2fWEetlxmR8sBHbHJDWZqOKGdsRJM0kfQAjCUJ43KX8s78ctnIz%2blp5xpYa4dSo1fjOKGM03i8jSeCMzGevHa2%2fBK5MNo1FdgN2JMqPLmHc0b6WTmiVbsGoTf5qv66Zq2t60x0wXZ2RKydiCJXh3CWVV1CWJgqanfl0%2bin8xutxYOvZL18NKUqPlvZR5el%2bVhYkAgZQdsA6fWVsZXE63W2itrTQ2cVaKV2CjSSqL1v9P%2fAXv4C"; // hand patched with lower case version of UrlEncode characters to match the .NET UrlDecode output

            var request = new HttpRequestData("GET", new Uri("http://localhost?SAMLRequest=" + serializedData));

            Saml2Binding.Get(Saml2BindingType.HttpRedirect).Unbind(request).Should().Be(xmlData);
        }
Пример #30
0
        public ValueTask <IdentityModel> LoginCallback(IdentityHttpRequest request)
        {
            var callbackBinding = Saml2Binding.GetBindingForRequest(request, BindingDirection.Response);

            callbackBinding.ValidateSignature(identityProviderCert, true);
            callbackBinding.Decrypt(serviceProviderCert, requiredEncryption);
            callbackBinding.ValidateFields(new string[] { redirectUrl });

            var callbackDocument = new Saml2AuthnResponse(callbackBinding);

            SamlIDManager.Validate(serviceProvider, callbackDocument.InResponseTo);

            if (callbackDocument.Audience != serviceProvider)
            {
                throw new IdentityProviderException("Saml Audience is not valid",
                                                    String.Format("Received: {0}, Expected: {1}", serviceProvider, callbackDocument.Audience));
            }

            if (String.IsNullOrWhiteSpace(callbackDocument.UserID))
            {
                return(new ValueTask <IdentityModel>((IdentityModel)null));
            }

            var identity = new IdentityModel()
            {
                UserID          = callbackDocument.UserID,
                UserName        = callbackDocument.UserName,
                Name            = callbackDocument.UserName,
                Roles           = callbackDocument.Roles,
                ServiceProvider = callbackDocument.Issuer,
                State           = null,
                OtherClaims     = null
            };

            return(new ValueTask <IdentityModel>(identity));
        }