예제 #1
0
        public async Task WsFederation_login_return_assertion_success()
        {
            var loginUrl = "/account/login?returnUrl=%2Fwsfederation%3Fwtrealm%3Durn%253Aowinrp%26wreply%3Dhttp%253A%252F%252Flocalhost%253A10313%252F%26wa%3Dwsignin1.0";
            var response = await _client.GetAsync(loginUrl);

            Assert.Equal(HttpStatusCode.Found, response.StatusCode);
            var wsEndpointUrl = "/wsfederation?wtrealm=urn%3Aowinrp&wreply=http%3A%2F%2Flocalhost%3A10313%2F&wa=wsignin1.0";

            Assert.Equal(wsEndpointUrl, response.Headers.Location.OriginalString);
            var request    = GetRequest(wsEndpointUrl, response);
            var wsResponse = await _client.SendAsync(request);

            Assert.Equal(HttpStatusCode.OK, wsResponse.StatusCode);
            var contentAsText = await wsResponse.Content.ReadAsStringAsync();

            Assert.Contains("action=\"http://localhost:10313/\"", contentAsText);
            var wreturn = ExtractInBetween(contentAsText, "wresult\" value=\"", "\"");

            Assert.False(wreturn.StartsWith("%EF%BB%BF")); //don't start with BOM (Byte Order Mark)
            var wsMessage = new WsFederationMessage
            {
                Wresult = WebUtility.HtmlDecode(wreturn),
            };
            var tokenString  = wsMessage.GetToken();
            var handler      = new SamlSecurityTokenHandler();
            var canReadToken = handler.CanReadToken(tokenString);

            Assert.True(canReadToken);
        }
예제 #2
0
        public void GetTokenParsingString(WsFederationMessageTheoryData theoryData)
        {
            var context = TestUtilities.WriteHeader($"{this}.GetTokenParsingString", theoryData);

            try
            {
                var token = WsFederationMessage.GetToken(theoryData.Wresult);
                if (token == null && theoryData.Token != null)
                {
                    context.AddDiff("(token == null && theoryData.Token != null)");
                }
                else if (token != null && theoryData.Token == null)
                {
                    context.AddDiff("(token != null && theoryData.Token == null)");
                }
                else if (string.Compare(token, theoryData.Token) != 0)
                {
                    context.AddDiff("string.Compare(token, token2) != 0");
                }

                theoryData.ExpectedException.ProcessNoException(context);
            }
            catch (Exception ex)
            {
                theoryData.ExpectedException.ProcessException(ex, context);
            }

            TestUtilities.AssertFailIfErrors(context);
        }
예제 #3
0
        public void GetTokenTest(WsFederationMessageTheoryData theoryData)
        {
            var context = TestUtilities.WriteHeader($"{this}.GetTokenTest", theoryData);

            try
            {
                // GetToken (for other than NETSTANDARD 1.4) uses XmlReaders to obtain token from Wresult.
                // GetToken(string) {internal} uses string manipulation to obtain token.
                // The result should be the same token.
                var tokenUsingReader = theoryData.WsFederationMessageTestSet.WsFederationMessage.GetToken();
                var tokenFromString  = WsFederationMessage.GetToken(theoryData.WsFederationMessageTestSet.WsFederationMessage.Wresult);
                if (string.Compare(tokenUsingReader, tokenFromString) != 0)
                {
                    context.AddDiff("string.Compare(tokenUsingReader, tokenFromString) != 0");
                }

                if (theoryData.TokenValidationParameters != null)
                {
                    var tokenHandler = new Saml2SecurityTokenHandler();
                    tokenHandler.ValidateToken(tokenUsingReader, theoryData.TokenValidationParameters, out SecurityToken validatedToken);
                }
                theoryData.ExpectedException.ProcessNoException(context);
            }
            catch (Exception ex)
            {
                theoryData.ExpectedException.ProcessException(ex, context);
            }

            TestUtilities.AssertFailIfErrors(context);
        }
        public async Task WsFederation_signin_request_with_wfresh_user_is_authenticated_wfresh_in_time_frame_return_assertion_success()
        {
            // login user
            var subjectId     = "user1";
            var loginUrl      = string.Format("/account/login?subjectId={0}", WebUtility.UrlEncode(subjectId));
            var loginResponse = await _client.GetAsync(loginUrl);

            var authTime = DateTime.UtcNow;

            // create ws fed sigin message with wfresh=5
            var wsMessage = new WsFederationMessage
            {
                Wa            = "wsignin1.0",
                IssuerAddress = "/wsfederation",
                Wtrealm       = "urn:owinrp",
                Wreply        = "http://localhost:10313/",
                Wfresh        = "5",
            };
            var signInUrl = wsMessage.CreateSignInUrl();
            var request   = new HttpRequestMessage(HttpMethod.Get, signInUrl);

            // test server doesnt save cookies between requests,
            // so we set them explicitly for the next request
            request.SetCookiesFromResponse(loginResponse);

            var response = await _client.SendAsync(request);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            var contentAsText = await response.Content.ReadAsStringAsync();

            Assert.NotEqual(String.Empty, contentAsText);
            Assert.Contains("action=\"http://localhost:10313/\"", contentAsText);

            // extract wreturn to use it later to check if our token is a valid token
            var wreturn           = ExtractInBetween(contentAsText, "wresult\" value=\"", "\"");
            var wsResponseMessage = new WsFederationMessage
            {
                Wresult = WebUtility.HtmlDecode(wreturn),
            };
            var tokenString  = wsResponseMessage.GetToken();
            var handler      = new SamlSecurityTokenHandler();
            var canReadToken = handler.CanReadToken(tokenString);

            Assert.True(canReadToken);
            var token          = handler.ReadSamlToken(tokenString);
            var authStatements = token.Assertion.Statements.OfType <SamlAuthenticationStatement>();

            Assert.Equal(1, authStatements.Count());
            var authStatement = authStatements.First();

            Assert.True(authStatement.AuthenticationInstant <= authTime.AddMinutes(5));
        }
        public async Task WsFederation_sigin_request_for_logged_in_user_return_assertion_success()
        {
            // login user
            var subjectId     = "user1";
            var loginUrl      = string.Format("/account/login?subjectId={0}", WebUtility.UrlEncode(subjectId));
            var loginResponse = await _client.GetAsync(loginUrl);

            Assert.Equal(HttpStatusCode.OK, loginResponse.StatusCode);

            // create ws fed sign in message
            var wsSignInMessage = new WsFederationMessage
            {
                Wa            = "wsignin1.0",
                IssuerAddress = "/wsfederation",
                Wtrealm       = "urn:owinrp",
                Wreply        = "http://localhost:10313/",
            };
            var signInUrl = wsSignInMessage.CreateSignInUrl();
            var request   = new HttpRequestMessage(HttpMethod.Get, signInUrl);

            // test server doesnt save cookies between requests,
            // so we set them explicitly for the next request
            request.SetCookiesFromResponse(loginResponse);

            // send ws fed sign in request
            var wsResponse = await _client.SendAsync(request);

            Assert.Equal(HttpStatusCode.OK, wsResponse.StatusCode);
            var contentAsText = await wsResponse.Content.ReadAsStringAsync();

            Assert.NotEqual(String.Empty, contentAsText);
            Assert.Contains("action=\"http://localhost:10313/\"", contentAsText);
            // extract wreturn to use it later to check if our token is a valid token
            var wreturn = ExtractInBetween(contentAsText, "wresult\" value=\"", "\"");

            Assert.False(wreturn.StartsWith("%EF%BB%BF")); //don't start with BOM (Byte Order Mark)
            var wsMessage = new WsFederationMessage
            {
                Wresult = WebUtility.HtmlDecode(wreturn),
            };
            var tokenString  = wsMessage.GetToken();
            var handler      = new SamlSecurityTokenHandler();
            var canReadToken = handler.CanReadToken(tokenString);

            Assert.True(canReadToken);
        }
예제 #6
0
        private async Task <SecurityTokenContext> RunSecurityTokenReceivedEventAsync(WsFederationMessage message)
        {
            Logger.LogTrace($"SecurityTokenReceived: {message.GetToken()}");
            var securityTokenContext = new SecurityTokenContext(Context, Options)
            {
                ProtocolMessage = message
            };

            await Options.Events.SecurityTokenReceived(securityTokenContext);

            if (securityTokenContext.HandledResponse)
            {
                Logger.LogDebug("SecurityTokenContext.HandledResponse");
            }
            else if (securityTokenContext.Skipped)
            {
                Logger.LogDebug("SecurityTokenContext.HandledResponse");
            }

            return(securityTokenContext);
        }
        public async Task WsFederation_signin_request_with_wfresh_set_to_0_user_is_authenticated_force_resignin_return_assertion_success()
        {
            // login user
            var subjectId     = "user1";
            var loginUrl      = string.Format("/account/login?subjectId={0}", WebUtility.UrlEncode(subjectId));
            var loginResponse = await _client.GetAsync(loginUrl);

            var authTime = DateTime.UtcNow;

            Thread.Sleep(3000); // TODO: bad workaround to sumulate login for 3 seconds

            // create ws fed sigin message with wfresh
            var wsMessage = new WsFederationMessage
            {
                Wa            = "wsignin1.0",
                IssuerAddress = "/wsfederation",
                Wtrealm       = "urn:owinrp",
                Wreply        = "http://localhost:10313/",
                Wfresh        = "0",
            };
            var uri     = wsMessage.CreateSignInUrl();
            var request = new HttpRequestMessage(HttpMethod.Get, uri);

            // test server doesnt save cookies between requests,
            // so we set them explicitly for the next request
            request.SetCookiesFromResponse(loginResponse);

            // make auth request, for allready logged in user
            var response = await _client.SendAsync(request);

            // redirect to sign in package because we enforce it with wfresh=0
            Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);

            uri     = response.Headers.Location.OriginalString + "&subjectId=" + subjectId;
            request = new HttpRequestMessage(HttpMethod.Get, uri);
            request.SetCookiesFromResponse(response);

            // login again to satisfy wfresh=0
            response = await _client.SendAsync(request);

            Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);

            uri     = response.Headers.Location.OriginalString;
            request = new HttpRequestMessage(HttpMethod.Get, uri);
            request.SetCookiesFromResponse(response);

            // do the redirect to auth endpoint
            response = await _client.SendAsync(request);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            var contentAsText = await response.Content.ReadAsStringAsync();

            Assert.NotEqual(String.Empty, contentAsText);
            Assert.Contains("action=\"http://localhost:10313/\"", contentAsText);

            // extract wreturn to use it later to check if our token is a valid token
            var wreturn           = ExtractInBetween(contentAsText, "wresult\" value=\"", "\"");
            var wsResponseMessage = new WsFederationMessage
            {
                Wresult = WebUtility.HtmlDecode(wreturn),
            };
            var tokenString  = wsResponseMessage.GetToken();
            var handler      = new SamlSecurityTokenHandler();
            var canReadToken = handler.CanReadToken(tokenString);

            Assert.True(canReadToken);
            var token          = handler.ReadSamlToken(tokenString);
            var authStatements = token.Assertion.Statements.OfType <SamlAuthenticationStatement>();

            Assert.Equal(1, authStatements.Count());
            var authStatement = authStatements.First();

            Assert.True(authStatement.AuthenticationInstant <= authTime.AddMinutes(5));
        }
        protected override async Task <AuthenticationTicket> AuthenticateCoreAsync()
        {
            // Allow login to be constrained to a specific path.
            if (Options.CallbackPath.HasValue && Options.CallbackPath != Request.Path)
            {
                return(null);
            }

            // assumption: if the ContentType is "application/x-www-form-urlencoded" it should be safe to read as it is small.
            if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase) &&
                !string.IsNullOrWhiteSpace(Request.ContentType)
                // May have media/type; charset=utf-8, allow partial match.
                && Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) &&
                Request.Body.CanRead)
            {
                if (!Request.Body.CanSeek)
                {
                    // Buffer in case this body was not meant for us.
                    MemoryStream memoryStream = new MemoryStream();
                    await Request.Body.CopyToAsync(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);
                    Request.Body = memoryStream;
                }
                IFormCollection form = await Request.ReadFormAsync();

                // Post preview release: a delegate on WsFederationAuthenticationOptions would allow for users to hook their own custom message.
                WsFederationMessage wsFederationMessage = new WsFederationMessage(form);
                if (!wsFederationMessage.IsSignInMessage)
                {
                    Request.Body.Seek(0, SeekOrigin.Begin);
                    return(null);
                }

                MessageReceivedNotification <WsFederationMessage> messageReceivedNotification = null;
                if (Options.Notifications != null && Options.Notifications.MessageReceived != null)
                {
                    messageReceivedNotification = new MessageReceivedNotification <WsFederationMessage> {
                        ProtocolMessage = wsFederationMessage
                    };
                    await Options.Notifications.MessageReceived(messageReceivedNotification);
                }

                if (messageReceivedNotification != null && messageReceivedNotification.Cancel)
                {
                    return(null);
                }

                if (wsFederationMessage.Wresult != null)
                {
                    string token = wsFederationMessage.GetToken();
                    if (Options.Notifications != null && Options.Notifications.SecurityTokenReceived != null)
                    {
                        SecurityTokenReceivedNotification securityTokenReceivedNotification = new SecurityTokenReceivedNotification {
                            SecurityToken = token
                        };
                        await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification);

                        if (securityTokenReceivedNotification.Cancel)
                        {
                            return(null);
                        }
                    }

                    ExceptionDispatchInfo authFailedEx = null;
                    try
                    {
                        ClaimsPrincipal principal      = Options.SecurityTokenHandlers.ValidateToken(token, Options.TokenValidationParameters);
                        ClaimsIdentity  claimsIdentity = principal.Identity as ClaimsIdentity;

                        // Retrieve our cached redirect uri
                        string state = wsFederationMessage.Wctx;
                        AuthenticationProperties properties = GetPropertiesFromWctx(state);

                        AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties);

                        Request.Context.Authentication.SignIn(claimsIdentity);
                        if (Options.Notifications != null && Options.Notifications.SecurityTokenValidated != null)
                        {
                            await Options.Notifications.SecurityTokenValidated(new SecurityTokenValidatedNotification { AuthenticationTicket = ticket });
                        }

                        return(ticket);
                    }
                    catch (Exception exception)
                    {
                        // We can't await inside a catch block, capture and handle outside.
                        authFailedEx = ExceptionDispatchInfo.Capture(exception);
                    }

                    if (authFailedEx != null)
                    {
                        if (Options.Notifications != null && Options.Notifications.AuthenticationFailed != null)
                        {
                            // Post preview release: user can update metadata, need consistent messaging.
                            var authenticationFailedNotification = new AuthenticationFailedNotification <WsFederationMessage>()
                            {
                                ProtocolMessage = wsFederationMessage,
                                Exception       = authFailedEx.SourceException
                            };

                            await Options.Notifications.AuthenticationFailed(authenticationFailedNotification);

                            if (!authenticationFailedNotification.Cancel)
                            {
                                authFailedEx.Throw();
                            }
                        }
                        else
                        {
                            authFailedEx.Throw();
                        }
                    }
                }
            }

            return(null);
        }