public async Task ReplyPathWillRejectIfAccessTokenIsMissing() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return(ReturnJsonResponse(new object())); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Contains("error=access_denied", transaction.Response.Headers.Location.ToString()); }
public async Task ReplyPathWillRejectIfCodeIsInvalid() { ISecureDataFormat <AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return(new HttpResponseMessage(HttpStatusCode.BadRequest)); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); transaction.Response.Headers.Location.ToString().ShouldContain("error=access_denied"); }
public async Task ChallengeCanSetUserStateThroughProperties(string userState) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("OIDCTest")); var settings = new TestSettings(o => { o.ClientId = "Test Id"; o.Authority = TestServerBuilder.DefaultAuthority; o.StateDataFormat = stateFormat; }); var properties = new AuthenticationProperties(); properties.Items.Add(OpenIdConnectDefaults.UserstatePropertiesKey, userState); var server = settings.CreateTestServer(properties); var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); var res = transaction.Response; Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); Assert.NotNull(res.Headers.Location); var values = settings.ValidateChallengeRedirect(res.Headers.Location); var actualState = values[OpenIdConnectParameterNames.State]; var actualProperties = stateFormat.Unprotect(actualState); Assert.Equal(userState ?? string.Empty, actualProperties.Items[OpenIdConnectDefaults.UserstatePropertiesKey]); }
public async Task ChallengeWillUseAuthenticationPropertiesParametersAsQueryArguments() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("MicrosoftTest")); using var host = await CreateHost(o => { o.ClientId = "Test Id"; o.ClientSecret = "Test Secret"; o.StateDataFormat = stateFormat; }); using var server = host.GetTestServer(); var transaction = await server.SendAsync("https://example.com/challenge"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); // verify query arguments var query = QueryHelpers.ParseQuery(transaction.Response.Headers.Location.Query); Assert.Equal("https://graph.microsoft.com/user.read", query["scope"]); Assert.Equal("consumers", query["domain_hint"]); Assert.Equal("username", query["login_hint"]); Assert.Equal("select_account", query["prompt"]); Assert.Equal("query", query["response_mode"]); // verify that the passed items were not serialized var stateProperties = stateFormat.Unprotect(query["state"]); Assert.DoesNotContain("scope", stateProperties.Items.Keys); Assert.DoesNotContain("domain_hint", stateProperties.Items.Keys); Assert.DoesNotContain("login_hint", stateProperties.Items.Keys); Assert.DoesNotContain("prompt", stateProperties.Items.Keys); Assert.DoesNotContain("response_mode", stateProperties.Items.Keys); }
public async Task SignOutWith_Specific_RedirectUri_From_Authentication_Properites() { var configuration = TestServerBuilder.CreateDefaultOpenIdConnectConfiguration(); var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("OIDCTest")); var server = TestServerBuilder.CreateServer(o => { o.Authority = TestServerBuilder.DefaultAuthority; o.StateDataFormat = stateFormat; o.ClientId = "Test Id"; o.Configuration = configuration; o.SignedOutRedirectUri = "https://example.com/postlogout"; }); var transaction = await server.SendAsync("https://example.com/signout_with_specific_redirect_uri"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); var query = transaction.Response.Headers.Location.Query.Substring(1).Split('&') .Select(each => each.Split('=')) .ToDictionary(pair => pair[0], pair => pair[1]); string redirectUri; Assert.True(query.TryGetValue("post_logout_redirect_uri", out redirectUri)); Assert.Equal(UrlEncoder.Default.Encode("https://example.com/signout-callback-oidc"), redirectUri, true); string state; Assert.True(query.TryGetValue("state", out state)); var properties = stateFormat.Unprotect(state); Assert.Equal("http://www.example.com/specific_redirect_uri", properties.RedirectUri, true); }
public DiscourseAuthenticationOptions() { CallbackPath = "/auth-discourse"; _nonceCookieBuilder = new DiscourseNonceCookieBuilder(this) { Name = ".CitizenFX.Discourse.Nonce.", HttpOnly = true, SameSite = SameSiteMode.None, SecurePolicy = CookieSecurePolicy.SameAsRequest, IsEssential = true, }; DataProtectionProvider = Microsoft.AspNetCore.DataProtection.DataProtectionProvider.Create("FXServer"); var dataProtector = DataProtectionProvider.CreateProtector( typeof(DiscourseAuthenticationHandler).FullName, typeof(string).FullName, "DAO", "v1"); StringDataFormat = new SecureDataFormat <string>(new StringSerializer(), dataProtector); StateDataFormat = new PropertiesDataFormat(dataProtector); }
public async Task CanRedirectOnError() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.Events = new OAuthEvents() { OnRemoteError = ctx => { ctx.Response.Redirect("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode(ctx.Error.Message)); ctx.HandleResponse(); return(Task.FromResult(0)); } }; }); //Post a message to the Google middleware var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode("The oauth state was missing or invalid."), transaction.Response.Headers.GetValues("Location").First()); }
public static AuthenticationProperties GetByCorrelationId(PropertiesDataFormat stateFormat, IList <string> cookies, string correlationId, string schemeName, string correlationCookieName = ".AspNetCore.Correlation") { var state = correlationId; var fullCookieValue = cookies.FirstOrDefault(x => x.StartsWith($"{correlationCookieName}.{schemeName}.{CorrelationMarker}.{state}")); var cookieValue = GetCookieValue(fullCookieValue, state); var stateProperties = stateFormat.Unprotect(cookieValue); return(stateProperties); }
public void ShorterStateTest(bool expected, string correlationId) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("WeixinAuthTest")); var properties = new AuthenticationProperties(); properties.Items[".xrsf"] = correlationId; var state = stateFormat.Protect(properties); Assert.Equal(expected, state.Length <= 128); }
public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return(new HttpResponseMessage(HttpStatusCode.BadRequest)); } }; if (redirect) { options.Events = new OAuthEvents() { OnRemoteError = ctx => { ctx.Response.Redirect("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode(ctx.Error.Message)); ctx.HandleResponse(); return(Task.FromResult(0)); } }; } }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); await Assert.ThrowsAsync <HttpRequestException>(() => server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue)); //var transaction = await server.SendAsync( // "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), // correlationKey + "=" + correlationValue); //if (redirect) //{ // Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); // Assert.Equal("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode("Access token was not found."), // transaction.Response.Headers.GetValues("Location").First()); //} //else //{ // Assert.Equal(HttpStatusCode.InternalServerError, transaction.Response.StatusCode); //} }
public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(new GoogleOptions { ClientId = "Test Id", ClientSecret = "Test Secret", StateDataFormat = stateFormat, BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return(ReturnJsonResponse(new { Error = "Error" }, HttpStatusCode.BadRequest)); } }, Events = redirect ? new OAuthEvents() { OnRemoteFailure = ctx => { ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message)); ctx.HandleResponse(); return(Task.FromResult(0)); } } : new OAuthEvents() }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var sendTask = server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), $".AspNetCore.Correlation.Google.{correlationValue}=N"); if (redirect) { var transaction = await sendTask; Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/error?FailureMessage=" + UrlEncoder.Default.Encode("OAuth token endpoint failure: Status: BadRequest;Headers: ;Body: {\"Error\":\"Error\"};"), transaction.Response.Headers.GetValues("Location").First()); } else { var error = await Assert.ThrowsAnyAsync <Exception>(() => sendTask); Assert.Equal("OAuth token endpoint failure: Status: BadRequest;Headers: ;Body: {\"Error\":\"Error\"};", error.GetBaseException().Message); } }
public async Task SignOutWithDefaultRedirectUri() { ISecureDataFormat <AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.Authority = "https://login.windows.net/common"; options.ClientId = "Test Id"; }); var transaction = await SendAsync(server, "https://example.com/signout"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); transaction.Response.Headers.Location.AbsoluteUri.ShouldBe("https://login.windows.net/common/oauth2/logout"); }
public async Task NoStateCauses500() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; }); //Post a message to the Google middleware var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode"); Assert.Equal(HttpStatusCode.InternalServerError, transaction.Response.StatusCode); }
public void ShorterState_GenerateCorrelationId_Test(bool expected, int len) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("WeixinAuthTest")); var properties = new AuthenticationProperties(); var cryptoRandom = RandomNumberGenerator.Create(); var bytes = new byte[len]; cryptoRandom.GetBytes(bytes); var correlationId = Base64UrlTextEncoder.Encode(bytes); properties.Items[".xrsf"] = correlationId; var state = stateFormat.Protect(properties); Assert.Equal(expected, state.Length <= 128); }
public void ShorterStateTest_WhereKeepRedirect(bool expected, int correlationIdGeneratorSize, int redirectUrlLen) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("WeixinAuthTest")); var properties = new AuthenticationProperties(); var cryptoRandom = RandomNumberGenerator.Create(); var bytes = new byte[correlationIdGeneratorSize]; cryptoRandom.GetBytes(bytes); var correlationId = Base64UrlTextEncoder.Encode(bytes); properties.Items[".xrsf"] = correlationId; var redirectUrl = new string('a', redirectUrlLen); properties.Items[".redirect"] = redirectUrl; var state = stateFormat.Protect(properties); Assert.Equal(expected, state.Length <= 128); }
public async Task OnRedirectToIdentityProviderEventCanSetState(string userState) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("OIDCTest")); var settings = new TestSettings(opt => { opt.StateDataFormat = stateFormat; opt.ClientId = "Test Id"; opt.Authority = TestServerBuilder.DefaultAuthority; opt.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = context => { context.ProtocolMessage.State = userState; return(Task.FromResult(0)); } }; }); var server = settings.CreateTestServer(); var transaction = await server.SendAsync(ChallengeEndpoint); var res = transaction.Response; Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); Assert.NotNull(res.Headers.Location); var values = settings.ValidateChallengeRedirect(res.Headers.Location); var actualState = values[OpenIdConnectParameterNames.State]; var actualProperties = stateFormat.Unprotect(actualState); if (userState != null) { Assert.Equal(userState, actualProperties.Items[OpenIdConnectDefaults.UserstatePropertiesKey]); } else { Assert.False(actualProperties.Items.ContainsKey(OpenIdConnectDefaults.UserstatePropertiesKey)); } }
public async Task ChallengeWillUseNotifications() { ISecureDataFormat <AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.Authority = "https://login.windows.net/common"; options.ClientId = "Test Id"; options.Notifications = new OpenIdConnectAuthenticationNotifications { MessageReceived = notification => { notification.ProtocolMessage.Scope = "test openid profile"; notification.HandleResponse(); return(Task.FromResult <object>(null)); } }; }); var properties = new AuthenticationProperties(); var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/challenge"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); }
public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return ReturnJsonResponse(new object()); } }; if (redirect) { options.Events = new OAuthEvents() { OnRemoteError = ctx => { ctx.Response.Redirect("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode(ctx.Error.Message)); ctx.HandleResponse(); return Task.FromResult(0); } }; } }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); if (redirect) { Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode("Access token was not found."), transaction.Response.Headers.GetValues("Location").First()); } else { Assert.Equal(HttpStatusCode.InternalServerError, transaction.Response.StatusCode); } }
public async Task NullRedirectUriWillRedirectToSlash() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" }); } else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") { return ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } }); } return null; } }; options.Events = new OAuthEvents { OnTicketReceived = context => { context.AuthenticationTicket.Properties.RedirectUri = null; return Task.FromResult(0); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains(correlationKey, transaction.SetCookie[0]); Assert.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); }
public async Task AuthenticatedEventCanGetRefreshToken() { ISecureDataFormat<AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("MsftTest")); var server = CreateServer( options => { options.ClientId = "Test Client Id"; options.ClientSecret = "Test Client Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://login.live.com/oauth20_token.srf") { return ReturnJsonResponse(new { access_token = "Test Access Token", expire_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" }); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://apis.live.net/v5.0/me") { return ReturnJsonResponse(new { id = "Test User ID", name = "Test Name", first_name = "Test Given Name", last_name = "Test Family Name", emails = new { preferred = "Test email" } }); } return null; } }; options.Notifications = new MicrosoftAccountAuthenticationNotifications { OnAuthenticated = context => { var refreshToken = context.RefreshToken; context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken) })); return Task.FromResult<object>(null); } }; }, context => { Describe(context.Response, context.User); return true; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Microsoft"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-microsoft?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); transaction.Response.Headers.Location.ToString().ShouldBe("/me"); transaction.SetCookie.Count.ShouldBe(2); transaction.SetCookie[0].ShouldContain(correlationKey); transaction.SetCookie[1].ShouldContain(".AspNet.External"); var authCookie = transaction.AuthenticationCookieValue; transaction = await SendAsync(server, "https://example.com/me", authCookie); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK); transaction.FindClaimValue("RefreshToken").ShouldBe("Test Refresh Token"); }
public async Task AuthenticatedEventCanGetRefreshToken() { ISecureDataFormat <AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("MsftTest")); var server = CreateServer( options => { options.ClientId = "Test Client Id"; options.ClientSecret = "Test Client Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://login.live.com/oauth20_token.srf") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expire_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" })); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://apis.live.net/v5.0/me") { return(ReturnJsonResponse(new { id = "Test User ID", name = "Test Name", first_name = "Test Given Name", last_name = "Test Family Name", emails = new { preferred = "Test email" } })); } return(null); } }; options.Notifications = new MicrosoftAccountAuthenticationNotifications { OnAuthenticated = context => { var refreshToken = context.RefreshToken; context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken) })); return(Task.FromResult <object>(null)); } }; }, context => { Describe(context.Response, context.User); return(true); }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Microsoft"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-microsoft?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); transaction.Response.Headers.Location.ToString().ShouldBe("/me"); transaction.SetCookie.Count.ShouldBe(2); transaction.SetCookie[0].ShouldContain(correlationKey); transaction.SetCookie[1].ShouldContain(".AspNet.External"); var authCookie = transaction.AuthenticationCookieValue; transaction = await SendAsync(server, "https://example.com/me", authCookie); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK); transaction.FindClaimValue("RefreshToken").ShouldBe("Test Refresh Token"); }
public async Task NullRedirectUriWillRedirectToSlash() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" })); } else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") { return(ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } })); } return(null); } }; options.Events = new OAuthEvents { OnTicketReceived = context => { context.AuthenticationTicket.Properties.RedirectUri = null; return(Task.FromResult(0)); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains(correlationKey, transaction.SetCookie[0]); Assert.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); }
public async Task ReplyPathWillRejectIfAccessTokenIsMissing() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return ReturnJsonResponse(new object()); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Contains("error=access_denied", transaction.Response.Headers.Location.ToString()); }
public async Task AuthenticatedEventCanGetRefreshToken() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(new GoogleOptions { ClientId = "Test Id", ClientSecret = "Test Secret", StateDataFormat = stateFormat, BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://www.googleapis.com/oauth2/v3/token") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" })); } else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") { return(ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } })); } throw new NotImplementedException(req.RequestUri.AbsoluteUri); } }, Events = new OAuthEvents { OnCreatingTicket = context => { var refreshToken = context.RefreshToken; context.Ticket.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Google") }, "Google")); return(Task.FromResult(0)); } } }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), $".AspNetCore.Correlation.Google.{correlationValue}=N"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains($".AspNetCore.Correlation.Google.{correlationValue}", transaction.SetCookie[0]); Assert.Contains(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/me", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal("Test Refresh Token", transaction.FindClaimValue("RefreshToken")); }
public async Task CanRedirectOnError() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.Events = new OAuthEvents() { OnRemoteError = ctx => { ctx.Response.Redirect("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode(ctx.Error.Message)); ctx.HandleResponse(); return Task.FromResult(0); } }; }); //Post a message to the Google middleware var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/error?ErrorMessage=" + UrlEncoder.Default.UrlEncode("The oauth state was missing or invalid."), transaction.Response.Headers.GetValues("Location").First()); }
public async Task ValidateAuthenticatedContext() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.AccessType = "offline"; options.Events = new OAuthEvents() { OnCreatingTicket = context => { Assert.NotNull(context.User); Assert.Equal(context.AccessToken, "Test Access Token"); Assert.Equal(context.RefreshToken, "Test Refresh Token"); Assert.Equal(context.ExpiresIn, TimeSpan.FromSeconds(3600)); Assert.Equal(GoogleHelper.GetEmail(context.User), "Test email"); Assert.Equal(GoogleHelper.GetId(context.User), "Test User ID"); Assert.Equal(GoogleHelper.GetName(context.User), "Test Name"); Assert.Equal(GoogleHelper.GetFamilyName(context.User), "Test Family Name"); Assert.Equal(GoogleHelper.GetGivenName(context.User), "Test Given Name"); return(Task.FromResult(0)); } }; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" })); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") { return(ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } })); } return(null); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/foo"; var state = stateFormat.Protect(properties); //Post a message to the Google middleware var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/foo", transaction.Response.Headers.GetValues("Location").First()); }
public async Task ReplyPathWillRejectIfCodeIsInvalid() { ISecureDataFormat<AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return new HttpResponseMessage(HttpStatusCode.BadRequest); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); transaction.Response.Headers.Location.ToString().ShouldContain("error=access_denied"); }
public async Task ChallengeWillUseNotifications() { ISecureDataFormat<AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.Authority = "https://login.windows.net/common"; options.ClientId = "Test Id"; options.Notifications = new OpenIdConnectAuthenticationNotifications { MessageReceived = notification => { notification.ProtocolMessage.Scope = "test openid profile"; notification.HandleResponse(); return Task.FromResult<object>(null); } }; }); var properties = new AuthenticationProperties(); var state = stateFormat.Protect(properties); var transaction = await SendAsync(server,"https://example.com/challenge"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); }
public async Task AuthenticatedEventCanGetRefreshToken() { ISecureDataFormat<AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return ReturnJsonResponse(new { access_token = "Test Access Token", expire_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" }); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") { return ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } }); } return null; } }; options.Notifications = new GoogleAuthenticationNotifications() { OnAuthenticated = context => { var refreshToken = context.RefreshToken; context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken) }, "Google")); return Task.FromResult<object>(null); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); transaction.Response.Headers.Location.ToString().ShouldBe("/me"); transaction.SetCookie.Count.ShouldBe(2); transaction.SetCookie[0].ShouldContain(correlationKey); transaction.SetCookie[1].ShouldContain(".AspNet.Cookie"); var authCookie = transaction.AuthenticationCookieValue; transaction = await SendAsync(server, "https://example.com/me", authCookie); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK); transaction.FindClaimValue("RefreshToken").ShouldBe("Test Refresh Token"); }
public async Task ValidateAuthenticatedContext() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.AccessType = "offline"; options.Events = new OAuthEvents() { OnCreatingTicket = context => { Assert.NotNull(context.User); Assert.Equal(context.AccessToken, "Test Access Token"); Assert.Equal(context.RefreshToken, "Test Refresh Token"); Assert.Equal(context.ExpiresIn, TimeSpan.FromSeconds(3600)); Assert.Equal(GoogleHelper.GetEmail(context.User), "Test email"); Assert.Equal(GoogleHelper.GetId(context.User), "Test User ID"); Assert.Equal(GoogleHelper.GetName(context.User), "Test Name"); Assert.Equal(GoogleHelper.GetFamilyName(context.User), "Test Family Name"); Assert.Equal(GoogleHelper.GetGivenName(context.User), "Test Given Name"); return Task.FromResult(0); } }; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" }); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") { return ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } }); } return null; } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/foo"; var state = stateFormat.Protect(properties); //Post a message to the Google middleware var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/foo", transaction.Response.Headers.GetValues("Location").First()); }
public async Task CustomUserInfoEndpointHasValidGraphQuery() { var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture"; string finalUserInfoEndpoint = string.Empty; var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("FacebookTest")); var server = CreateServer( app => { app.UseFacebookAuthentication(options => { options.AppId = "Test App Id"; options.AppSecret = "Test App Secret"; options.StateDataFormat = stateFormat; options.UserInformationEndpoint = customUserInfoEndpoint; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.GetLeftPart(UriPartial.Path) == FacebookDefaults.TokenEndpoint) { var res = new HttpResponseMessage(HttpStatusCode.OK); var tokenResponse = new Dictionary<string, string> { { "access_token", "TestAuthToken" }, }; res.Content = new FormUrlEncodedContent(tokenResponse); return res; } if (req.RequestUri.GetLeftPart(UriPartial.Path) == new Uri(customUserInfoEndpoint).GetLeftPart(UriPartial.Path)) { finalUserInfoEndpoint = req.RequestUri.ToString(); var res = new HttpResponseMessage(HttpStatusCode.OK); var graphResponse = JsonConvert.SerializeObject(new { id = "TestProfileId", name = "TestName" }); res.Content = new StringContent(graphResponse, Encoding.UTF8); return res; } return null; } }; }); app.UseCookieAuthentication(); }, services => { services.AddAuthentication(); }, handler: null); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Facebook"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(1, finalUserInfoEndpoint.Count(c => c == '?')); Assert.Contains("fields=email,timezone,picture", finalUserInfoEndpoint); Assert.Contains("&access_token=", finalUserInfoEndpoint); }
public async Task CustomUserInfoEndpointHasValidGraphQuery() { var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture"; var finalUserInfoEndpoint = string.Empty; var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("FacebookTest")); using var host = await CreateHost( app => app.UseAuthentication(), services => { services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie() .AddFacebook(o => { o.AppId = "Test App Id"; o.AppSecret = "Test App Secret"; o.StateDataFormat = stateFormat; o.UserInformationEndpoint = customUserInfoEndpoint; o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == FacebookDefaults.TokenEndpoint) { var res = new HttpResponseMessage(HttpStatusCode.OK); var graphResponse = "{ \"access_token\": \"TestAuthToken\" }"; res.Content = new StringContent(graphResponse, Encoding.UTF8); return(res); } if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == new Uri(customUserInfoEndpoint).GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)) { finalUserInfoEndpoint = req.RequestUri.ToString(); var res = new HttpResponseMessage(HttpStatusCode.OK); var graphResponse = "{ \"id\": \"TestProfileId\", \"name\": \"TestName\" }"; res.Content = new StringContent(graphResponse, Encoding.UTF8); return(res); } return(null); } }; }); }, handler : null); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); using var server = host.GetTestServer(); var transaction = await server.SendAsync( "https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.Encode(state), $".AspNetCore.Correlation.{correlationValue}=N"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(1, finalUserInfoEndpoint.Count(c => c == '?')); Assert.Contains("fields=email,timezone,picture", finalUserInfoEndpoint); Assert.Contains("&access_token=", finalUserInfoEndpoint); Assert.Contains("&appsecret_proof=b7fb6d5a4510926b4af6fe080497827d791dc45fe6541d88ba77bdf6e8e208c6&", finalUserInfoEndpoint); }
public async Task AuthenticatedEventCanGetRefreshToken() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("MsftTest")); var server = CreateServer( options => { options.ClientId = "Test Client Id"; options.ClientSecret = "Test Client Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://login.live.com/oauth20_token.srf") { return ReturnJsonResponse(new { access_token = "Test Access Token", expire_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" }); } else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://apis.live.net/v5.0/me") { return ReturnJsonResponse(new { id = "Test User ID", name = "Test Name", first_name = "Test Given Name", last_name = "Test Family Name", emails = new { preferred = "Test email" } }); } return null; } }; options.Events = new OAuthEvents { OnCreatingTicket = context => { var refreshToken = context.RefreshToken; context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Microsoft") }, "Microsoft")); return Task.FromResult<object>(null); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Microsoft"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains(correlationKey, transaction.SetCookie[0]); Assert.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/me", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal("Test Refresh Token", transaction.FindClaimValue("RefreshToken")); }
public async Task NoStateCauses500() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; }); //Post a message to the Google middleware var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode"); Assert.Equal(HttpStatusCode.InternalServerError, transaction.Response.StatusCode); }
public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string claimsIssuer) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.ClaimsIssuer = claimsIssuer; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer" }); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") { return ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } }); } return null; } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains(correlationKey, transaction.SetCookie[0]); Assert.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/me", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); var expectedIssuer = claimsIssuer ?? GoogleDefaults.AuthenticationScheme; Assert.Equal("Test Name", transaction.FindClaimValue(ClaimTypes.Name, expectedIssuer)); Assert.Equal("Test User ID", transaction.FindClaimValue(ClaimTypes.NameIdentifier, expectedIssuer)); Assert.Equal("Test Given Name", transaction.FindClaimValue(ClaimTypes.GivenName, expectedIssuer)); Assert.Equal("Test Family Name", transaction.FindClaimValue(ClaimTypes.Surname, expectedIssuer)); Assert.Equal("Test email", transaction.FindClaimValue(ClaimTypes.Email, expectedIssuer)); // Ensure claims transformation Assert.Equal("yup", transaction.FindClaimValue("xform")); }
public async Task AuthenticatedEventCanGetRefreshToken() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("MsftTest")); var server = CreateServer( options => { options.ClientId = "Test Client Id"; options.ClientSecret = "Test Client Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://login.live.com/oauth20_token.srf") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expire_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" })); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://apis.live.net/v5.0/me") { return(ReturnJsonResponse(new { id = "Test User ID", name = "Test Name", first_name = "Test Given Name", last_name = "Test Family Name", emails = new { preferred = "Test email" } })); } return(null); } }; options.Events = new OAuthEvents { OnCreatingTicket = context => { var refreshToken = context.RefreshToken; context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Microsoft") }, "Microsoft")); return(Task.FromResult <object>(null)); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Microsoft"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains(correlationKey, transaction.SetCookie[0]); Assert.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/me", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal("Test Refresh Token", transaction.FindClaimValue("RefreshToken")); }
public async Task AuthenticatedEventCanGetRefreshToken() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" }); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") { return ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } }); } return null; } }; options.Events = new OAuthEvents { OnCreatingTicket = context => { var refreshToken = context.RefreshToken; context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Google") }, "Google")); return Task.FromResult<object>(null); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains(correlationKey, transaction.SetCookie[0]); Assert.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/me", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal("Test Refresh Token", transaction.FindClaimValue("RefreshToken")); }
public async Task AuthenticatedEventCanGetRefreshToken() { ISecureDataFormat <AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expire_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" })); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") { return(ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } })); } return(null); } }; options.Notifications = new GoogleAuthenticationNotifications() { OnAuthenticated = context => { var refreshToken = context.RefreshToken; context.Identity.AddClaim(new Claim("RefreshToken", refreshToken)); return(Task.FromResult <object>(null)); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); transaction.Response.Headers.Location.ToString().ShouldBe("/me"); transaction.SetCookie.Count.ShouldBe(2); transaction.SetCookie[0].ShouldContain(correlationKey); transaction.SetCookie[1].ShouldContain(".AspNet.Cookie"); var authCookie = transaction.AuthenticationCookieValue; transaction = await SendAsync(server, "https://example.com/me", authCookie); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK); transaction.FindClaimValue("RefreshToken").ShouldBe("Test Refresh Token"); }
public async Task AuthenticatedEventCanGetRefreshToken() { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("MsftTest")); var server = CreateServer(o => { o.ClientId = "Test Client Id"; o.ClientSecret = "Test Client Secret"; o.StateDataFormat = stateFormat; o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://login.microsoftonline.com/common/oauth2/v2.0/token") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expire_in = 3600, token_type = "Bearer", refresh_token = "Test Refresh Token" })); } else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://graph.microsoft.com/v1.0/me") { return(ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", givenName = "Test Given Name", surname = "Test Family Name", mail = "Test email" })); } return(null); } }; o.Events = new OAuthEvents { OnCreatingTicket = context => { var refreshToken = context.RefreshToken; context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Microsoft") }, "Microsoft")); return(Task.FromResult <object>(null)); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.Encode(state), $".AspNetCore.Correlation.Microsoft.{correlationValue}=N"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains($".AspNetCore.Correlation.Microsoft.{correlationValue}", transaction.SetCookie[0]); Assert.Contains(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/me", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); Assert.Equal("Test Refresh Token", transaction.FindClaimValue("RefreshToken")); }
public async Task CustomUserInfoEndpointHasValidGraphQuery() { var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture"; var finalUserInfoEndpoint = string.Empty; var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("FacebookTest")); var server = CreateServer( app => { app.UseCookieAuthentication(); app.UseFacebookAuthentication(new FacebookOptions { AppId = "Test App Id", AppSecret = "Test App Secret", StateDataFormat = stateFormat, UserInformationEndpoint = customUserInfoEndpoint, BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == FacebookDefaults.TokenEndpoint) { var res = new HttpResponseMessage(HttpStatusCode.OK); var graphResponse = JsonConvert.SerializeObject(new { access_token = "TestAuthToken" }); res.Content = new StringContent(graphResponse, Encoding.UTF8); return(res); } if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == new Uri(customUserInfoEndpoint).GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)) { finalUserInfoEndpoint = req.RequestUri.ToString(); var res = new HttpResponseMessage(HttpStatusCode.OK); var graphResponse = JsonConvert.SerializeObject(new { id = "TestProfileId", name = "TestName" }); res.Content = new StringContent(graphResponse, Encoding.UTF8); return(res); } return(null); } } }); }, services => { services.AddAuthentication(options => options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); }, handler: null); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.Encode(state), $".AspNetCore.Correlation.Facebook.{correlationValue}=N"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(1, finalUserInfoEndpoint.Count(c => c == '?')); Assert.Contains("fields=email,timezone,picture", finalUserInfoEndpoint); Assert.Contains("&access_token=", finalUserInfoEndpoint); }
public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string claimsIssuer) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(options => { options.ClientId = "Test Id"; options.ClientSecret = "Test Secret"; options.StateDataFormat = stateFormat; options.ClaimsIssuer = claimsIssuer; options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { return(ReturnJsonResponse(new { access_token = "Test Access Token", expires_in = 3600, token_type = "Bearer" })); } else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") { return(ReturnJsonResponse(new { id = "Test User ID", displayName = "Test Name", name = new { familyName = "Test Family Name", givenName = "Test Given Name" }, url = "Profile link", emails = new[] { new { value = "Test email", type = "account" } } })); } return(null); } }; }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var transaction = await server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), correlationKey + "=" + correlationValue); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); Assert.Equal(2, transaction.SetCookie.Count); Assert.Contains(correlationKey, transaction.SetCookie[0]); Assert.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/me", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); var expectedIssuer = claimsIssuer ?? GoogleDefaults.AuthenticationScheme; Assert.Equal("Test Name", transaction.FindClaimValue(ClaimTypes.Name, expectedIssuer)); Assert.Equal("Test User ID", transaction.FindClaimValue(ClaimTypes.NameIdentifier, expectedIssuer)); Assert.Equal("Test Given Name", transaction.FindClaimValue(ClaimTypes.GivenName, expectedIssuer)); Assert.Equal("Test Family Name", transaction.FindClaimValue(ClaimTypes.Surname, expectedIssuer)); Assert.Equal("Test email", transaction.FindClaimValue(ClaimTypes.Email, expectedIssuer)); // Ensure claims transformation Assert.Equal("yup", transaction.FindClaimValue("xform")); }
public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect) { var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); var server = CreateServer(new GoogleOptions { ClientId = "Test Id", ClientSecret = "Test Secret", StateDataFormat = stateFormat, BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return ReturnJsonResponse(new object()); } }, Events = redirect ? new OAuthEvents() { OnRemoteFailure = ctx => { ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message)); ctx.HandleResponse(); return Task.FromResult(0); } } : new OAuthEvents() }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; var correlationValue = "TestCorrelationId"; properties.Items.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; var state = stateFormat.Protect(properties); var sendTask = server.SendAsync( "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), $".AspNetCore.Correlation.Google.{correlationValue}=N"); if (redirect) { var transaction = await sendTask; Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal("/error?FailureMessage=" + UrlEncoder.Default.Encode("Failed to retrieve access token."), transaction.Response.Headers.GetValues("Location").First()); } else { var error = await Assert.ThrowsAnyAsync<Exception>(() => sendTask); Assert.Equal("Failed to retrieve access token.", error.GetBaseException().Message); } }