Esempio n. 1
0
        private static CommandResult ProcessResponse(
            IOptions options,
            Saml2Response samlResponse,
            StoredRequestState storedRequestState)
        {
            var principal = new ClaimsPrincipal(samlResponse.GetClaims(options, storedRequestState?.RelayData));

            if (options.SPOptions.ReturnUrl == null)
            {
                if (storedRequestState == null)
                {
                    throw new ConfigurationErrorsException(UnsolicitedMissingReturnUrlMessage);
                }
                if (storedRequestState.ReturnUrl == null)
                {
                    throw new ConfigurationErrorsException(SpInitiatedMissingReturnUrl);
                }
            }

            options.SPOptions.Logger.WriteInformation("Successfully processed SAML response " + samlResponse.Id
                                                      + " and authenticated " + principal.FindFirst(ClaimTypes.NameIdentifier)?.Value);

            return(new CommandResult()
            {
                HttpStatusCode = HttpStatusCode.SeeOther,
                Location = storedRequestState?.ReturnUrl ?? options.SPOptions.ReturnUrl,
                Principal = principal,
                RelayData = storedRequestState?.RelayData,
                SessionNotOnOrAfter = samlResponse.SessionNotOnOrAfter
            });
        }
        public void HttpRequestData_Ctor_Deserialize_StoredRequestState()
        {
            var    url     = new Uri("http://example.com:42/ApplicationPath/Path?RelayState=Foo");
            string appPath = "/ApplicationPath";

            var storedRequestData = new StoredRequestState(
                new EntityId("http://idp.example.com"),
                new Uri("http://sp.example.com/loggedout"),
                new Saml2Id("id123"),
                null);

            var cookies = new KeyValuePair <string, string>[]
            {
                new KeyValuePair <string, string>(
                    "Kentor.Foo",
                    HttpRequestData.ConvertBinaryData(
                        StubDataProtector.Protect(storedRequestData.Serialize())))
            };

            var subject = new HttpRequestData(
                "GET",
                url,
                appPath,
                Enumerable.Empty <KeyValuePair <string, string[]> >(),
                cookies,
                StubDataProtector.Unprotect);

            subject.StoredRequestState.ShouldBeEquivalentTo(storedRequestData);
        }
Esempio n. 3
0
        private void Init(
            string httpMethod,
            Uri url,
            string applicationPath,
            IEnumerable <KeyValuePair <string, IEnumerable <string> > > formData,
            Func <string, string> cookieReader,
            Func <byte[], byte[]> cookieDecryptor,
            ClaimsPrincipal user)
        {
            InitBasicFields(httpMethod, url, applicationPath, formData);
            User = user;

            var relayState = QueryString["RelayState"].SingleOrDefault();

            if (relayState == null)
            {
                Form.TryGetValue("RelayState", out relayState);
            }
            RelayState = relayState;

            if (relayState != null)
            {
                var cookieName = StoredRequestState.CookieNameBase + relayState;
                var cookieData = cookieReader(cookieName);
                if (!string.IsNullOrEmpty(cookieData))
                {
                    byte[] encryptedData = GetBinaryData(cookieData);

                    var decryptedData = cookieDecryptor(encryptedData);

                    StoredRequestState = new StoredRequestState(decryptedData);
                }
            }
        }
        public async static Task <HttpRequestData> ToHttpRequestData(this IOwinContext context)
        {
            if (context == null)
            {
                return(null);
            }

            IFormCollection formData = null;

            if (context.Request.Body != null)
            {
                formData = await context.Request.ReadFormAsync();
            }

            var applicationRootPath = context.Request.PathBase.Value;

            if (string.IsNullOrEmpty(applicationRootPath))
            {
                applicationRootPath = "/";
            }

            StoredRequestState storedRequestState = null; // TODO: implement storage for the request state

            return(new HttpRequestData(
                       context.Request.Method,
                       context.Request.Uri,
                       applicationRootPath,
                       formData,
                       storedRequestState));
        }
Esempio n. 5
0
        private static XmlElement ResolveArtifact(
            string artifact,
            StoredRequestState storedRequestState,
            IOptions options)
        {
            var binaryArtifact = Convert.FromBase64String(artifact);
            var idp            = GetIdp(binaryArtifact, storedRequestState, options);
            var arsIndex       = (binaryArtifact[2] << 8) | binaryArtifact[3];
            var arsUri         = idp.ArtifactResolutionServiceUrls[arsIndex];

            var payload = new Saml2ArtifactResolve
            {
                Artifact = artifact,
                Issuer   = options.SPOptions.EntityId
            }.ToXml();

            var signingServiceCertificate = options.SPOptions.SigningServiceCertificate;
            var resolver = options.SPOptions.ArtifactResolver;

            options.SPOptions.Logger.WriteVerbose("Calling idp " + idp.EntityId.Id + " to resolve artifact\n" + artifact);

            var response =
                Saml2SoapBinding.SendSoapRequest(payload, arsUri, signingServiceCertificate, resolver);

            options.SPOptions.Logger.WriteVerbose("Artifact resolved returned\n" + response);

            return(new Saml2ArtifactResponse(response).GetMessage());
        }
Esempio n. 6
0
        private void ValidateInResponseTo(IOptions options)
        {
            if (InResponseTo == null)
            {
                if (options.IdentityProviders[Issuer].AllowUnsolicitedAuthnResponse)
                {
                    return;
                }
                string msg = string.Format(CultureInfo.InvariantCulture,
                                           "Unsolicited responses are not allowed for idp \"{0}\".", Issuer.Id);
                throw new Saml2ResponseFailedValidationException(msg);
            }
            else
            {
                StoredRequestState storedRequestState;
                bool knownInResponseToId = PendingAuthnRequests.TryRemove(InResponseTo, out storedRequestState);
                if (!knownInResponseToId)
                {
                    string msg = string.Format(CultureInfo.InvariantCulture,
                                               "Replayed or unknown InResponseTo \"{0}\".", InResponseTo);

                    throw new Saml2ResponseFailedValidationException(msg);
                }
                requestState = storedRequestState;
                if (requestState.Idp.Id != Issuer.Id)
                {
                    var msg = string.Format(CultureInfo.InvariantCulture,
                                            "Expected response from idp \"{0}\" but received response from idp \"{1}\".",
                                            requestState.Idp.Id, issuer.Id);
                    throw new Saml2ResponseFailedValidationException(msg);
                }
            }
        }
Esempio n. 7
0
        private static XmlElement ResolveArtifact(
            string artifact,
            StoredRequestState storedRequestState,
            IOptions options)
        {
            var binaryArtifact = Convert.FromBase64String(artifact);
            var idp            = GetIdp(binaryArtifact, storedRequestState, options);
            var arsIndex       = (binaryArtifact[2] << 8) | binaryArtifact[3];
            var arsUri         = idp.ArtifactResolutionServiceUrls[arsIndex];

            var payload = new Saml2ArtifactResolve()
            {
                Artifact = artifact,
                Issuer   = options.SPOptions.EntityId
            }.ToXml();

            if (options.SPOptions.SigningServiceCertificate != null)
            {
                var xmlDoc = XmlHelpers.XmlDocumentFromString(payload);
                xmlDoc.Sign(options.SPOptions.SigningServiceCertificate, true);
                payload = xmlDoc.OuterXml;
            }

            options.SPOptions.Logger.WriteVerbose("Calling idp " + idp.EntityId.Id + " to resolve artifact\n" + artifact);

            var clientCertificates = options.SPOptions.ServiceCertificates
                                     .Where(sc => sc.Use.HasFlag(CertificateUse.TlsClient) && sc.Status == CertificateStatus.Current)
                                     .Select(sc => sc.Certificate);

            var response = Saml2SoapBinding.SendSoapRequest(payload, arsUri, clientCertificates);

            options.SPOptions.Logger.WriteVerbose("Artifact resolved returned\n" + response);

            return(new Saml2ArtifactResponse(response).GetMessage());
        }
        private static XmlElement ResolveArtifact(
            string artifact,
            StoredRequestState storedRequestState,
            IOptions options)
        {
            var binaryArtifact = Convert.FromBase64String(artifact);
            var idp            = GetIdp(binaryArtifact, storedRequestState, options);
            var arsIndex       = (binaryArtifact[2] << 8) | binaryArtifact[3];
            var arsUri         = idp.ArtifactResolutionServiceUrls[arsIndex];

            var payload = new Saml2ArtifactResolve()
            {
                Artifact = artifact,
                Issuer   = options.SPOptions.EntityId
            }.ToXml();

            if (options.SPOptions.SigningServiceCertificate != null)
            {
                var xmlDoc = new XmlDocument()
                {
                    PreserveWhitespace = true
                };

                xmlDoc.LoadXml(payload);
                xmlDoc.Sign(options.SPOptions.SigningServiceCertificate, true);
                payload = xmlDoc.OuterXml;
            }

            var response = Saml2SoapBinding.SendSoapRequest(payload, arsUri);

            return(new Saml2ArtifactResponse(response).GetMessage());
        }
Esempio n. 9
0
        public async Task Saml2Handler_RedirectsToDefaultIdpOnChallenge()
        {
            var context = new Saml2HandlerTestContext();

            var authProps = new AuthenticationProperties()
            {
                IssuedUtc   = new DateTimeOffset(new DateTime(2017, 09, 30)),
                RedirectUri = "https://sp.example.com/LoggedIn"
            };

            var response = context.HttpContext.Response;

            string cookieData = null;

            response.Cookies.Append(
                Arg.Any <string>(),
                Arg.Do <string>(v => cookieData = v),
                Arg.Any <CookieOptions>());

            await context.Subject.ChallengeAsync(authProps);

            response.StatusCode.Should().Be(303);
            response.Headers["Location"].Single()
            .Should().StartWith("https://idp.example.com/sso?SAMLRequest=");

            var state = new StoredRequestState(StubDataProtector.Unprotect(
                                                   HttpRequestData.GetBinaryData(cookieData)));

            state.ReturnUrl.OriginalString.Should().Be("https://sp.example.com/LoggedIn");

            // Don't dual-store the return-url.
            state.RelayData.Values.Should().NotContain("https://sp.example.com/LoggedIn");
        }
Esempio n. 10
0
        private static CommandResult HandleResponse(UnbindResult unbindResult, StoredRequestState storedRequestState, IOptions options, Uri returnUrl)
        {
            var logoutResponse = Saml2LogoutResponse.FromXml(unbindResult.Data);
            var notificationHandledTheStatus = options.Notifications.ProcessSingleLogoutResponseStatus(logoutResponse, storedRequestState);

            if (!notificationHandledTheStatus)
            {
                var status = logoutResponse.Status;
                if (status != Saml2StatusCode.Success)
                {
                    throw new UnsuccessfulSamlOperationException(string.Format(CultureInfo.InvariantCulture,
                                                                               "Idp returned status \"{0}\", indicating that the single logout failed. The local session has been successfully terminated.",
                                                                               status));
                }
            }

            var commandResult = new CommandResult
            {
                HttpStatusCode = HttpStatusCode.SeeOther
            };

            if (!options.SPOptions.Compatibility.DisableLogoutStateCookie)
            {
                commandResult.ClearCookieName = StoredRequestState.CookieNameBase + unbindResult.RelayState;
            }
            commandResult.Location = storedRequestState?.ReturnUrl ?? returnUrl;

            options.SPOptions.Logger.WriteInformation("Received logout response " + logoutResponse.Id
                                                      + ", redirecting to " + commandResult.Location);

            return(commandResult);
        }
        public void HttpRequestData_Ctor_Deserialize_StoredRequestState()
        {
            var url = new Uri("http://example.com:42/ApplicationPath/Path?RelayState=Foo");
            string appPath = "/ApplicationPath";

            var storedRequestData = new StoredRequestState(
                    new EntityId("http://idp.example.com"),
                    new Uri("http://sp.example.com/loggedout"),
                    new Saml2Id("id123"),
                    null);

            var cookies = new KeyValuePair<string, string>[]
            {
                new KeyValuePair<string, string>(
                    "Kentor.Foo",
                    HttpRequestData.ConvertBinaryData(
                            StubDataProtector.Protect(storedRequestData.Serialize())))
            };

            var subject = new HttpRequestData(
                 "GET",
                 url,
                 appPath,
                 Enumerable.Empty<KeyValuePair<string, string[]>>(),
                 cookies,
                 StubDataProtector.Unprotect);

            subject.StoredRequestState.ShouldBeEquivalentTo(storedRequestData);
        }
Esempio n. 12
0
        private IEnumerable <ClaimsIdentity> CreateClaims(StoredRequestState storedRequestState, IOptions options)
        {
            Validate(storedRequestState, options);

            if (status != Saml2StatusCode.Success)
            {
                throw new InvalidOperationException("The Saml2Response must have status success to extract claims.");
            }

            foreach (XmlElement assertionNode in AllAssertionElementNodes)
            {
                using (var reader = new FilteringXmlNodeReader(SignedXml.XmlDsigNamespaceUrl, "Signature", assertionNode))
                {
                    var handler = options.SPOptions.Saml2PSecurityTokenHandler;

                    var token = (Saml2SecurityToken)handler.ReadToken(reader);
                    handler.DetectReplayedToken(token);

                    var validateAudience = token.Assertion.Conditions.AudienceRestrictions.Count > 0;

                    handler.ValidateConditions(token.Assertion.Conditions, validateAudience);

                    yield return(handler.CreateClaims(token));
                }
            }
        }
Esempio n. 13
0
        private void Init(
            string httpMethod,
            Uri url,
            string applicationPath,
            IEnumerable <KeyValuePair <string, string[]> > formData,
            IEnumerable <KeyValuePair <string, string> > cookies,
            Func <byte[], byte[]> cookieDecryptor,
            ClaimsPrincipal user)
        {
            InitBasicFields(httpMethod, url, applicationPath, formData);
            User = user;

            var relayState = QueryString["RelayState"].SingleOrDefault();

            if (relayState == null)
            {
                Form.TryGetValue("RelayState", out relayState);
            }

            if (relayState != null)
            {
                var cookieName = "Kentor." + relayState;
                if (cookies.Any(c => c.Key == cookieName))
                {
                    var    cookieData    = cookies.SingleOrDefault(c => c.Key == cookieName).Value;
                    byte[] encryptedData = GetBinaryData(cookieData);

                    var decryptedData = cookieDecryptor(encryptedData);

                    StoredRequestState = new StoredRequestState(decryptedData);
                }
            }
        }
Esempio n. 14
0
 private void Validate(StoredRequestState storedRequestState, IOptions options)
 {
     if (!validated)
     {
         try
         {
             ValidateInResponseTo(storedRequestState, options);
             ValidateSignature(options);
         }
         catch (Saml2ResponseFailedValidationException ex)
         {
             validationException = ex;
             throw;
         }
         finally
         {
             validated = true;
         }
     }
     else
     {
         if (validationException != null)
         {
             throw validationException;
         }
     }
 }
Esempio n. 15
0
        private static CommandResult ProcessResponse(
            IOptions options,
            Saml2Response samlResponse,
            StoredRequestState storedRequestState)
        {
            var principal = new ClaimsPrincipal(samlResponse.GetClaims(options));

            principal = options.SPOptions.SystemIdentityModelIdentityConfiguration
                        .ClaimsAuthenticationManager.Authenticate(null, principal);

            if (options.SPOptions.ReturnUrl == null)
            {
                if (storedRequestState == null)
                {
                    throw new ConfigurationErrorsException(UnsolicitedMissingReturnUrlMessage);
                }
                if (storedRequestState.ReturnUrl == null)
                {
                    throw new ConfigurationErrorsException(SpInitiatedMissingReturnUrl);
                }
            }

            return(new CommandResult()
            {
                HttpStatusCode = HttpStatusCode.SeeOther,
                Location = storedRequestState == null?null:storedRequestState.ReturnUrl ?? options.SPOptions.ReturnUrl,
                Principal = principal,
                RelayData = storedRequestState == null?null:storedRequestState.RelayData
            });
        }
Esempio n. 16
0
        public async Task Saml2Handler_ChallengeAsync_UsesCurrentUrlAsReturnUrlIfAuthPropsAreMissing()
        {
            var context = new Saml2HandlerTestContext();

            var response = context.HttpContext.Response;

            string cookieData = null;

            response.Cookies.Append(
                Arg.Any <string>(),
                Arg.Do <string>(v => cookieData = v),
                Arg.Any <CookieOptions>());

            await context.Subject.ChallengeAsync(null);

            response.StatusCode.Should().Be(303);
            response.Headers["Location"].Single()
            .Should().StartWith("https://idp.example.com/sso?SAMLRequest=");

            var state = new StoredRequestState(StubDataProtector.Unprotect(
                                                   HttpRequestData.GetBinaryData(cookieData)));

            state.ReturnUrl.OriginalString.Should().Be("https://sp.example.com/somePath?param=value");

            // Don't dual-store the return-url.
            state.RelayData.Values.Should().NotContain("https://sp.example.com/somePath?param=value");
        }
Esempio n. 17
0
        private static Uri GetLocation(StoredRequestState storedRequestState, IdentityProvider identityProvider,
                                       string relayState, IOptions options)
        {
            // When SP-Initiated
            if (storedRequestState != null)
            {
                return(storedRequestState.ReturnUrl ?? options.SPOptions.ReturnUrl);
            }
            else
            {
                //When IDP-Initiated

                if (identityProvider.RelayStateUsedAsReturnUrl)
                {
                    if (!PathHelper.IsLocalWebUrl(relayState))
                    {
                        if (!options.Notifications.ValidateAbsoluteReturnUrl(relayState))
                        {
                            throw new InvalidOperationException("Return Url must be a relative Url.");
                        }
                    }

                    return(new Uri(relayState, UriKind.RelativeOrAbsolute));
                }
            }

            return(options.SPOptions.ReturnUrl);
        }
Esempio n. 18
0
        private static CommandResult RedirectToDiscoveryService(
            string returnPath,
            SPOptions spOptions,
            Saml2Urls saml2Urls,
            IDictionary <string, string> relayData)
        {
            string returnUrl = saml2Urls.SignInUrl.OriginalString;

            var relayState = SecureKeyGenerator.CreateRelayState();

            returnUrl += "?RelayState=" + Uri.EscapeDataString(relayState);

            var redirectLocation = string.Format(
                CultureInfo.InvariantCulture,
                "{0}?entityID={1}&return={2}&returnIDParam=idp",
                spOptions.DiscoveryServiceUrl,
                Uri.EscapeDataString(spOptions.EntityId.Id),
                Uri.EscapeDataString(returnUrl));

            var requestState = new StoredRequestState(
                null,
                returnPath == null ? null : new Uri(returnPath, UriKind.RelativeOrAbsolute),
                null,
                relayData);

            return(new CommandResult()
            {
                HttpStatusCode = HttpStatusCode.SeeOther,
                Location = new Uri(redirectLocation),
                RequestState = requestState,
                SetCookieName = StoredRequestState.CookieNameBase + relayState
            });
        }
Esempio n. 19
0
 public HttpRequestData(
     string httpMethod,
     Uri url,
     string applicationPath,
     IEnumerable <KeyValuePair <string, string[]> > formData, StoredRequestState storedRequestState)
 {
     Init(httpMethod, url, applicationPath, formData, storedRequestState);
 }
 public void PendingAuthnRequests_Add_ThrowsOnExisting()
 {
     var id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));
     PendingAuthnRequests.Add(id, requestData);
     Action a = () => PendingAuthnRequests.Add(id, requestData);
     a.ShouldThrow<InvalidOperationException>();
 }
 public void PendingAuthnRequests_Remove_FalseOnRemovedTwice()
 {
     var id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));
     StoredRequestState responseData;
     PendingAuthnRequests.Add(id, requestData);
     PendingAuthnRequests.TryRemove(id, out responseData).Should().BeTrue();
     PendingAuthnRequests.TryRemove(id, out responseData).Should().BeFalse();
 }
Esempio n. 22
0
 // Used by tests.
 internal HttpRequestData(
     string httpMethod,
     Uri url,
     string applicationPath,
     IEnumerable <KeyValuePair <string, string[]> > formData,
     StoredRequestState storedRequestState)
 {
     InitBasicFields(httpMethod, url, applicationPath, formData);
     StoredRequestState = storedRequestState;
 }
        public void PendingAuthnRequests_Add_ThrowsOnExisting()
        {
            var id          = new Saml2Id();
            var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));

            PendingAuthnRequests.Add(id, requestData);
            Action a = () => PendingAuthnRequests.Add(id, requestData);

            a.ShouldThrow <InvalidOperationException>();
        }
        public void PendingAuthnRequests_Remove_FalseOnRemovedTwice()
        {
            var id          = new Saml2Id();
            var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));
            StoredRequestState responseData;

            PendingAuthnRequests.Add(id, requestData);
            PendingAuthnRequests.TryRemove(id, out responseData).Should().BeTrue();
            PendingAuthnRequests.TryRemove(id, out responseData).Should().BeFalse();
        }
Esempio n. 25
0
 // Used by tests.
 internal HttpRequestData(
     string httpMethod,
     Uri url,
     string applicationPath,
     IEnumerable<KeyValuePair<string, string[]>> formData,
     StoredRequestState storedRequestState)
 {
     InitBasicFields(httpMethod, url, applicationPath, formData);
     StoredRequestState = storedRequestState;
 }
        private void PrepareArtifactState(string RelayState, EntityId idp)
        {
            var storedState = new StoredRequestState(
                idp,
                new Uri("http://return.org"),
                new Saml2Id(),
                null);

            PendingAuthnRequests.Add(RelayState, storedState);
        }
 /// <summary>
 /// Stores the StoredRequestState using the Saml2Id
 /// </summary>
 /// <param name="id"></param>
 /// <param name="idp"></param>
 public void Add(Saml2Id id, StoredRequestState idp)
 {
     lock (PendingAuthnInMemoryContainer.Container)
     {
         if (PendingAuthnInMemoryContainer.Container.ContainsKey(id))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         PendingAuthnInMemoryContainer.Container.Add(id, idp);
     }
 }
 //private static readonly Dictionary<Saml2Id, StoredRequestState> pendingAuthnRequest = new Dictionary<Saml2Id, StoredRequestState>();
 internal static void Add(Saml2Id id, StoredRequestState idp)
 {
     lock (pendingRequestCache)
     {
         if (pendingRequestCache.Contains(id.Value))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         pendingRequestCache.Add(id.Value, idp, new CacheItemPolicy { });
     }
 }
Esempio n. 29
0
        private static byte[] Serialize(StoredRequestState obj)
        {
            using (var stream = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(stream, obj);
                stream.Flush();

                return(stream.ToArray());
            }
        }
 /// <summary>
 /// Stores the StoredRequestState using the Saml2Id
 /// </summary>
 /// <param name="id">The Saml2Id used as key to store the pending authentication data.</param>
 /// <param name="idp">The state of the pending authentication request.</param>
 public void Add(Saml2Id id, StoredRequestState idp)
 {
     lock (container)
     {
         if (container.ContainsKey(id))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         container.Add(id, idp);
     }
 }
 internal static void Add(Saml2Id id, StoredRequestState idp)
 {
     lock (pendingAuthnRequest)
     {
         if (pendingAuthnRequest.ContainsKey(id))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         pendingAuthnRequest.Add(id, idp);
     }
 }
Esempio n. 32
0
 internal static void Add(string id, StoredRequestState idp)
 {
     lock (pendingAuthnRequest)
     {
         if (pendingAuthnRequest.ContainsKey(id))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         pendingAuthnRequest.Add(id, idp);
     }
 }
 public void PendingAuthnInMemoryStorage_AddRemove()
 {
     var id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));
     var container = new PendingAuthnInMemoryStorage();
     container.Add(id, requestData);
     StoredRequestState responseData;
     container.TryRemove(id, out responseData).Should().BeTrue();
     responseData.Should().Be(requestData);
     responseData.Idp.Id.Should().Be("testidp");
     responseData.ReturnUrl.Should().Be("http://localhost/Return.aspx");
 }
 /// <summary>
 /// Returns the Stored Request State while simultaneously deleting it from storage.
 /// </summary>
 /// <param name="id"></param>
 /// <param name="idp"></param>
 /// <returns></returns>
 public bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (PendingAuthnInMemoryContainer.Container)
     {
         if (id != null && PendingAuthnInMemoryContainer.Container.ContainsKey(id))
         {
             idp = PendingAuthnInMemoryContainer.Container[id];
             return(PendingAuthnInMemoryContainer.Container.Remove(id));
         }
         idp = null;
         return(false);
     }
 }
 /// <summary>
 /// Returns the Stored Request State while simultaneously deleting it from storage. 
 /// </summary>
 /// <param name="id">The Saml2Id key used to retrieve the pending authentication data.</param>
 /// <param name="idp">The state of the pending authentication request.</param>
 /// <returns></returns>
 public bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (container)
     {
         if (id != null && container.ContainsKey(id))
         {
             idp = container[id];
             return container.Remove(id);
         }
         idp = null;
         return false;
     }
 }
 public void PendingAuthnRequests_AddRemove()
 {
     var relayState = RelayStateGenerator.CreateSecureKey();
     var saml2Id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"), saml2Id);
     PendingAuthnRequests.Add(relayState, requestData);
     StoredRequestState responseData;
     PendingAuthnRequests.TryRemove(relayState, out responseData).Should().BeTrue();
     responseData.Should().Be(requestData);
     responseData.Idp.Id.Should().Be("testidp");
     responseData.ReturnUrl.Should().Be("http://localhost/Return.aspx");
     responseData.MessageId.Should().Be(saml2Id);
 }
        public void PendingAuthnRequests_Remove_FalseOnRemovedTwice()
        {
            var relayState = RelayStateGenerator.CreateSecureKey();
            var requestData = new StoredRequestState(
                new EntityId("testidp"),
                new Uri("http://localhost/Return.aspx"),
                new Saml2Id());

            StoredRequestState responseData;
            PendingAuthnRequests.Add(relayState, requestData);
            PendingAuthnRequests.TryRemove(relayState, out responseData).Should().BeTrue();
            PendingAuthnRequests.TryRemove(relayState, out responseData).Should().BeFalse();
        }
Esempio n. 38
0
 internal static bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (pendingAuthnRequest)
     {
         if (id != null && pendingAuthnRequest.ContainsKey(id))
         {
             idp = pendingAuthnRequest[id];
             return(pendingAuthnRequest.Remove(id));
         }
         idp = null;
         return(false);
     }
 }
 /// <summary>
 /// Returns the Stored Request State while simultaneously deleting it from storage. 
 /// </summary>
 /// <param name="id"></param>
 /// <param name="idp"></param>
 /// <returns></returns>
 public bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (PendingAuthnInMemoryContainer.Container)
     {
         if (id != null && PendingAuthnInMemoryContainer.Container.ContainsKey(id))
         {
             idp = PendingAuthnInMemoryContainer.Container[id];
             return PendingAuthnInMemoryContainer.Container.Remove(id);
         }
         idp = null;
         return false;
     }
 }
Esempio n. 40
0
 internal static bool TryRemove(string id, out StoredRequestState state)
 {
     lock (pendingAuthnRequest)
     {
         if (id != null && pendingAuthnRequest.ContainsKey(id))
         {
             state = pendingAuthnRequest[id];
             return(pendingAuthnRequest.Remove(id));
         }
         state = null;
         return(false);
     }
 }
 internal static bool TryRemove(string id, out StoredRequestState state)
 {
     lock (pendingAuthnRequest)
     {
         if (id != null && pendingAuthnRequest.ContainsKey(id))
         {
             state = pendingAuthnRequest[id];
             return pendingAuthnRequest.Remove(id);
         }
         state = null;
         return false;
     }
 }
Esempio n. 42
0
        public void PendingAuthnRequests_AddRemove()
        {
            var id          = new Saml2Id();
            var requestData = new StoredRequestState("testidp", new Uri("http://localhost/Return.aspx"));

            PendingAuthnRequests.Add(id, requestData);
            StoredRequestState responseData;

            PendingAuthnRequests.TryRemove(id, out responseData).Should().BeTrue();
            responseData.Should().Be(requestData);
            responseData.Idp.Should().Be("testidp");
            responseData.ReturnUri.Should().Be("http://localhost/Return.aspx");
        }
 internal static bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (pendingAuthnRequest)
     {
         if (id != null && pendingAuthnRequest.ContainsKey(id))
         {
             idp = pendingAuthnRequest[id];
             return pendingAuthnRequest.Remove(id);
         }
         idp = null;
         return false;
     }
 }
 internal static bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (pendingRequestCache)
     {
         if (id != null && pendingRequestCache.Contains(id.Value))
         {
             idp = pendingRequestCache[id.Value] as StoredRequestState;
             pendingRequestCache.Remove(id.Value);
             return true;
         }
         idp = null;
         return false;
     }
 }
        public void PendingAuthnRequests_Remove_FalseOnRemovedTwice()
        {
            var relayState  = RelayStateGenerator.CreateSecureKey();
            var requestData = new StoredRequestState(
                new EntityId("testidp"),
                new Uri("http://localhost/Return.aspx"),
                new Saml2Id());

            StoredRequestState responseData;

            PendingAuthnRequests.Add(relayState, requestData);
            PendingAuthnRequests.TryRemove(relayState, out responseData).Should().BeTrue();
            PendingAuthnRequests.TryRemove(relayState, out responseData).Should().BeFalse();
        }
        public async Task OwinContextExtensionsTests_ToHttpRequestData_ReadsRelayStateCookie()
        {
            var ctx = OwinTestHelpers.CreateOwinContext();
            ctx.Request.QueryString = new QueryString("RelayState", "SomeState");

            var storedRequestState = new StoredRequestState(
                null, new Uri("http://sp.example.com"), null, null);

            var cookieData = HttpRequestData.ConvertBinaryData(
                    StubDataProtector.Protect(storedRequestState.Serialize()));

            ctx.Request.Headers["Cookie"] = $"Kentor.SomeState={cookieData}";

            var actual = await ctx.ToHttpRequestData(StubDataProtector.Unprotect);

            actual.StoredRequestState.ShouldBeEquivalentTo(storedRequestState);
        }
Esempio n. 47
0
        private static CommandResult ProcessResponse(
            IOptions options,
            Saml2Response samlResponse,
            StoredRequestState storedRequestState)
        {
            var principal = new ClaimsPrincipal(samlResponse.GetClaims(options));

            principal = options.SPOptions.SystemIdentityModelIdentityConfiguration
                .ClaimsAuthenticationManager.Authenticate(null, principal);

            if(options.SPOptions.ReturnUrl == null)
            {
                if (storedRequestState == null)
                {
                    throw new ConfigurationErrorsException(UnsolicitedMissingReturnUrlMessage);
                }
                if(storedRequestState.ReturnUrl == null)
                {
                    throw new ConfigurationErrorsException(SpInitiatedMissingReturnUrl);
                }
            }

            return new CommandResult()
            {
                HttpStatusCode = HttpStatusCode.SeeOther,
                Location = storedRequestState?.ReturnUrl ?? options.SPOptions.ReturnUrl,
                Principal = principal,
                RelayData = storedRequestState?.RelayData,
                SessionNotOnOrAfter = samlResponse.SessionNotOnOrAfter
            };
        }
Esempio n. 48
0
        private void ValidateInResponseTo(IOptions options)
        {
            if (InResponseTo == null)
            {
                if (options.IdentityProviders[Issuer].AllowUnsolicitedAuthnResponse)
                {
                    return;
                }
                string msg = string.Format(CultureInfo.InvariantCulture,
                    "Unsolicited responses are not allowed for idp \"{0}\".", Issuer.Id);
                throw new Saml2ResponseFailedValidationException(msg);
            }
            else
            {
                StoredRequestState storedRequestState;
                bool knownInResponseToId = PendingAuthnRequests.TryRemove(InResponseTo, out storedRequestState);
                if (!knownInResponseToId)
                {
                    string msg = string.Format(CultureInfo.InvariantCulture,
                        "Replayed or unknown InResponseTo \"{0}\".", InResponseTo);

                    throw new Saml2ResponseFailedValidationException(msg);
                }
                requestState = storedRequestState;
                if (requestState.Idp.Id != Issuer.Id)
                {
                    var msg = string.Format(CultureInfo.InvariantCulture,
                        "Expected response from idp \"{0}\" but received response from idp \"{1}\".",
                        requestState.Idp.Id, issuer.Id);
                    throw new Saml2ResponseFailedValidationException(msg);
                }
            }
        }
Esempio n. 49
0
        private void Init(
            string httpMethod,
            Uri url,
            string applicationPath,
            IEnumerable<KeyValuePair<string, string[]>> formData,
            IEnumerable<KeyValuePair<string, string>> cookies,
            Func<byte[], byte[]> cookieDecryptor,
            ClaimsPrincipal user)
        {
            InitBasicFields(httpMethod, url, applicationPath, formData);
            User = user;

            var relayState = QueryString["RelayState"].SingleOrDefault();
            if(relayState == null)
            {
                Form.TryGetValue("RelayState", out relayState);
            }
            RelayState = relayState;

            if (relayState != null)
            {
                var cookieName = "Kentor." + relayState;
                if (cookies.Any(c => c.Key == cookieName))
                {
                    var cookieData = cookies.SingleOrDefault(c => c.Key == cookieName).Value;
                    byte[] encryptedData = GetBinaryData(cookieData);

                    var decryptedData = cookieDecryptor(encryptedData);

                    StoredRequestState = new StoredRequestState(decryptedData);
                }
            }
        }
Esempio n. 50
0
        private static CommandResult HandleResponse(UnbindResult unbindResult, StoredRequestState storedRequestState, IOptions options, Uri returnUrl)
        {
            var status = Saml2LogoutResponse.FromXml(unbindResult.Data).Status;
            if(status != Saml2StatusCode.Success)
            {
                throw new UnsuccessfulSamlOperationException(string.Format(CultureInfo.InvariantCulture,
                    "Idp returned status \"{0}\", indicating that the single logout failed. The local session has been successfully terminated.",
                    status));
            }

            var commandResult = new CommandResult
            {
                HttpStatusCode = HttpStatusCode.SeeOther
            };
            if (!options.SPOptions.Compatibility.DisableLogoutStateCookie)
            {
                commandResult.ClearCookieName = "Kentor." + unbindResult.RelayState;
            }
            commandResult.Location = storedRequestState?.ReturnUrl ?? returnUrl;
            return commandResult;
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke_UsesAuthPropsReturnUrl()
        {
            var authPropsReturnUrl = "http://sp.exmample.com/AuthPropsLogout";

            var revoke = new AuthenticationResponseRevoke(
                new string[0],
                new AuthenticationProperties { RedirectUri = authPropsReturnUrl });

            var options = new KentorAuthServicesAuthenticationOptions(true);
            options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/ExternalPath/");

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(303, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();
            context.Response.Headers["Location"] = "http://sp.example.com/locationHeader";
            context.Request.User = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
                {
                    new Claim(AuthServicesClaimTypes.LogoutNameIdentifier, ",,,,NameId", null, "https://idp.example.com"),
                    new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
                }, "Federation"));

            await subject.Invoke(context);

            var cookieValue = context.Response.Headers["Set-Cookie"].Split(';', '=')[1];

            var returnUrl = new StoredRequestState(options.DataProtector.Unprotect(
                HttpRequestData.GetBinaryData(cookieValue))).ReturnUrl;

            returnUrl.Should().Be(authPropsReturnUrl);
        }
        private async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke_PreservesRedirect(
            string location, string expectedUrl, string path = "/Account/LogOut")
        {
            var revoke = new AuthenticationResponseRevoke(new string[0]);

            var options = new KentorAuthServicesAuthenticationOptions(true);
            ((SPOptions)options.SPOptions).PublicOrigin = new Uri("https://sp.example.com/ExternalPath/");

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(303, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Scheme = "http";
            context.Request.Host = new HostString("sp-internal.example.com");
            context.Request.PathBase = new PathString("/AppPath");
            context.Request.Path = new PathString(path);
            context.Response.Headers["Location"] = location;

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

            var cookieValue = context.Response.Headers["Set-Cookie"].Split(';', '=')[1]
                .Replace('_', '/').Replace('-', '+').Replace('.', '=');

            var returnUrl = new StoredRequestState(options.DataProtector.Unprotect(
                Convert.FromBase64String(cookieValue))).ReturnUrl;

            returnUrl.Should().Be(expectedUrl);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_AcsWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            var authProps = new AuthenticationProperties()
            {
                IssuedUtc = new DateTime(1975, 05, 05, 05, 05, 05, DateTimeKind.Utc)
            };
            authProps.Dictionary["Test"] = "TestValue";

            var state = new StoredRequestState(new EntityId("https://idp.example.com"),
                new Uri("http://localhost/LoggedIn"),
                new Saml2Id("InResponseToId"),
                authProps.Dictionary);

            var relayState = SecureKeyGenerator.CreateRelayState();

            var cookieData = HttpRequestData.ConvertBinaryData(
                CreateAppBuilder().CreateDataProtector(
                    typeof(KentorAuthServicesAuthenticationMiddleware).FullName)
                    .Protect(state.Serialize()));

            context.Request.Headers["Cookie"] = $"Kentor.{relayState}={cookieData}";

            var response =
            @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
                xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
                ID = """ + MethodBase.GetCurrentMethod().Name + @""" Version=""2.0""
                IssueInstant=""2013-01-01T00:00:00Z"" InResponseTo=""InResponseToId"" >
                <saml2:Issuer>
                    https://idp.example.com
                </saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
                </saml2p:Status>
                <saml2:Assertion
                Version=""2.0"" ID=""" + MethodBase.GetCurrentMethod().Name + @"_Assertion1""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] { 
                new KeyValuePair<string, string>("SAMLResponse", 
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response)))),
                new KeyValuePair<string, string>("RelayState",relayState)
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices/Acs");

            var signInAsAuthenticationType = "AuthType";
            var ids = new ClaimsIdentity[] { new ClaimsIdentity(signInAsAuthenticationType),
                new ClaimsIdentity(signInAsAuthenticationType) };
            ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager", 
                null, "ClaimsAuthenticationManagerStub"));

            var subject = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                StubFactory.CreateOwinOptions());

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");
            context.Response.Headers["Set-Cookie"].Should().Be($"Kentor.{relayState}=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT");

            context.Authentication.AuthenticationResponseGrant.Principal.Identities
                .ShouldBeEquivalentTo(ids, opt => opt.IgnoringCyclicReferences());

            context.Authentication.AuthenticationResponseGrant.Properties.RedirectUri
                .Should().Be("http://localhost/LoggedIn", 
                "the StoredRequestState.ReturnUrl should overtake the value in the AuthProperties and be stored in the AuthProps");

            context.Authentication.AuthenticationResponseGrant.Properties.Dictionary["Test"]
                .Should().Be("TestValue");

            context.Authentication.AuthenticationResponseGrant.Properties.IssuedUtc
                .Should().Be(authProps.IssuedUtc);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_AcsWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            var state = new StoredRequestState(new EntityId("https://idp.example.com"),
                new Uri("http://localhost/LoggedIn"),
                new Saml2Id(MethodBase.GetCurrentMethod().Name + "RequestID"),
                new AuthenticationProperties());

            ((AuthenticationProperties)state.RelayData).RedirectUri = state.ReturnUrl.OriginalString;
            ((AuthenticationProperties)state.RelayData).Dictionary["Test"] = "TestValue";

            var relayState = RelayStateGenerator.CreateSecureKey();

            PendingAuthnRequests.Add(relayState, state);

            var response =
            @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
                xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
                ID = """ + MethodBase.GetCurrentMethod().Name + @""" Version=""2.0""
                IssueInstant=""2013-01-01T00:00:00Z"" InResponseTo=""" + MethodBase.GetCurrentMethod().Name + @"RequestID"" >
                <saml2:Issuer>
                    https://idp.example.com
                </saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
                </saml2p:Status>
                <saml2:Assertion
                Version=""2.0"" ID=""" + MethodBase.GetCurrentMethod().Name + @"_Assertion1""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] { 
                new KeyValuePair<string, string>("SAMLResponse", 
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response)))),
                new KeyValuePair<string, string>("RelayState",relayState)
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices/Acs");

            var signInAsAuthenticationType = "AuthType";
            var ids = new ClaimsIdentity[] { new ClaimsIdentity(signInAsAuthenticationType),
                new ClaimsIdentity(signInAsAuthenticationType) };
            ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager", 
                null, "ClaimsAuthenticationManagerStub"));

            var middleware = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                StubFactory.CreateOwinOptions());

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(302);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");

            context.Authentication.AuthenticationResponseGrant.Principal.Identities
                .ShouldBeEquivalentTo(ids, opt => opt.IgnoringCyclicReferences());

            context.Authentication.AuthenticationResponseGrant.Properties.RedirectUri
                .Should().Be("http://localhost/LoggedIn");

            context.Authentication.AuthenticationResponseGrant.Properties.Dictionary["Test"]
                .Should().Be("TestValue");
        }
        private void TestSerializeDeserialize(StoredRequestState subject)
        {
            var actual = new StoredRequestState(subject.Serialize());

            actual.ShouldBeEquivalentTo(subject);
        }
        private void PrepareArtifactState(string RelayState, EntityId idp)
        {
            var storedState = new StoredRequestState(
                idp,
                new Uri("http://return.org"),
                new Saml2Id(),
                null);

            PendingAuthnRequests.Add(RelayState, storedState);
        }
Esempio n. 57
0
 internal static void Add(string id, StoredRequestState state)
 {
     ((IDictionary<string, StoredRequestState>)pendingAuthnRequest).Add(id, state);
 }
Esempio n. 58
0
 internal static bool TryRemove(string id, out StoredRequestState state)
 {
     state = null;
     return pendingAuthnRequest.TryRemove(id, out state);
 }