public async Task <IActionResult> Index() { // GET + no parameters = metadata request if (!Request.QueryString.HasValue) { _logger.LogDebug("Start WS-Federation metadata request"); var entity = await _metadata.GenerateAsync(Url.Action("Index", "WsFederation", null, Request.Scheme, Request.Host.Value)); return(new MetadataResult(entity)); } var url = Url.Action("Index", "WsFederation", null, Request.Scheme, Request.Host.Value) + Request.QueryString; _logger.LogDebug("Start WS-Federation request: {url}", url); // user can be null here (this differs from HttpContext.User where the anonymous user is filled in) var user = await _userSession.GetUserAsync(); WsFederationMessage message = WsFederationMessage.FromUri(new Uri(url)); var isSignin = message.IsSignInMessage; if (isSignin) { return(await ProcessSignInAsync(message, user)); } var isSignout = message.IsSignOutMessage; if (isSignout) { return(await ProcessSignOutAsync(message)); } return(BadRequest("Invalid WS-Federation request")); }
/// <summary> /// Handles wsignoutcleanup1.0 messages sent to the RemoteSignOutPath /// </summary> /// <returns></returns> protected virtual async Task <bool> HandleRemoteSignOutAsync() { var message = new WsFederationMessage(Request.Query.Select(pair => new KeyValuePair <string, string[]>(pair.Key, pair.Value))); var remoteSignOutContext = new RemoteSignOutContext(Context, Scheme, Options, message); await Events.RemoteSignOut(remoteSignOutContext); if (remoteSignOutContext.Result != null) { if (remoteSignOutContext.Result.Handled) { Logger.RemoteSignOutHandledResponse(); return(true); } if (remoteSignOutContext.Result.Skipped) { Logger.RemoteSignOutSkipped(); return(false); } } Logger.RemoteSignOut(); await Context.SignOutAsync(Options.SignOutScheme); return(true); }
public void ConstructorTest(WsFederationMessageTheoryData theoryData) { TestUtilities.WriteHeader($"{this}.ConstructorTest", theoryData); try { // check default constructor var wsFederationMessage1 = new WsFederationMessage { IssuerAddress = theoryData.IssuerAddress, Wreply = theoryData.Wreply, Wct = theoryData.Wct }; Assert.Equal(theoryData.IssuerAddress, wsFederationMessage1.IssuerAddress); Assert.Equal(theoryData.Wreply, wsFederationMessage1.Wreply); Assert.Equal(theoryData.Wct, wsFederationMessage1.Wct); // check copy constructor WsFederationMessage wsFederationMessage2 = new WsFederationMessage(wsFederationMessage1); Assert.Equal(theoryData.IssuerAddress, wsFederationMessage2.IssuerAddress); Assert.Equal(theoryData.Wreply, wsFederationMessage2.Wreply); Assert.Equal(theoryData.Wct, wsFederationMessage2.Wct); theoryData.ExpectedException.ProcessNoException(); } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex); } }
public void Publics() { string issuerAdderss = @"http://www.gotjwt.com"; string wreply = @"http://www.relyingparty.com"; string wct = Guid.NewGuid().ToString(); WsFederationMessage wsFederationMessage = new WsFederationMessage { IssuerAddress = issuerAdderss, Wreply = wreply, Wct = wct, }; wsFederationMessage.SetParameter("bob", null); wsFederationMessage.Parameters.Add("bob", null); string uriString = wsFederationMessage.BuildRedirectUrl(); Uri uri = new Uri(uriString); WsFederationMessage wsFederationMessageReturned = WsFederationMessage.FromQueryString(uri.Query); wsFederationMessageReturned.IssuerAddress = issuerAdderss; wsFederationMessageReturned.Parameters.Add("bob", null); Assert.IsTrue(MessageComparer.AreEqual(wsFederationMessage, wsFederationMessageReturned)); wsFederationMessageReturned = WsFederationMessage.FromUri(uri); wsFederationMessageReturned.IssuerAddress = issuerAdderss; wsFederationMessageReturned.Parameters.Add("bob", null); Assert.IsTrue(MessageComparer.AreEqual(wsFederationMessage, wsFederationMessageReturned)); }
public void WaSignIn(WsFederationMessageTheoryData theoryData) { var context = TestUtilities.WriteHeader($"{this}.WaSignIn", theoryData); try { var fedMessage = WsFederationMessage.FromQueryString(theoryData.QueryString); var token = fedMessage.GetToken(); if (theoryData.TokenValidationParameters != null) { theoryData.SecurityTokenHandler.ValidateToken(token, theoryData.TokenValidationParameters, out SecurityToken validatedToken); if (theoryData.SecurityToken != null) { IdentityComparer.AreEqual(theoryData.SecurityToken, validatedToken, context); } } theoryData.ExpectedException.ProcessNoException(context); } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex, context); } TestUtilities.AssertFailIfErrors(context); }
/// <summary> /// Handles wsignoutcleanup1.0 messages sent to the RemoteSignOutPath /// </summary> /// <returns></returns> protected virtual async Task <bool> HandleRemoteSignOutAsync() { // ToArray handles the StringValues.IsNullOrEmpty case. We assume non-empty Value does not contain null elements. #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. var message = new WsFederationMessage(Request.Query.Select(pair => new KeyValuePair <string, string[]>(pair.Key, pair.Value.ToArray()))); #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. var remoteSignOutContext = new RemoteSignOutContext(Context, Scheme, Options, message); await Events.RemoteSignOut(remoteSignOutContext); if (remoteSignOutContext.Result != null) { if (remoteSignOutContext.Result.Handled) { Logger.RemoteSignOutHandledResponse(); return(true); } if (remoteSignOutContext.Result.Skipped) { Logger.RemoteSignOutSkipped(); return(false); } } Logger.RemoteSignOut(); await Context.SignOutAsync(Options.SignOutScheme); return(true); }
private static WsFederationMessage CreateResponse(SignInValidationResult validationResult, SecurityToken token) { var handler = CreateTokenHandler(validationResult.RelyingParty.TokenType); var client = validationResult.Client; var message = validationResult.WsFederationMessage; var rstr = new RequestSecurityTokenResponse { CreatedAt = token.ValidFrom, ExpiresAt = token.ValidTo, AppliesTo = client.ClientId, Context = message.Wctx, ReplyTo = validationResult.ReplyUrl, RequestedSecurityToken = token, SecurityTokenHandler = handler, }; var responseMessage = new WsFederationMessage { IssuerAddress = message.Wreply ?? client.RedirectUris.First(), Wa = WsFederationConstants.WsFederationActions.SignIn, Wresult = rstr.Serialize(), Wctx = message.Wctx }; return(responseMessage); }
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); }
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); }
/// <summary> /// Handles Challenge /// </summary> /// <returns></returns> protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); } // Save the original challenge URI so we can redirect back to it when we're done. if (string.IsNullOrEmpty(properties.RedirectUri)) { properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString; } var wsFederationMessage = new WsFederationMessage() { IssuerAddress = _configuration.TokenEndpoint ?? string.Empty, Wtrealm = Options.Wtrealm, Wa = WsFederationConstants.WsFederationActions.SignIn, }; if (!string.IsNullOrEmpty(Options.Wreply)) { wsFederationMessage.Wreply = Options.Wreply; } else { wsFederationMessage.Wreply = BuildRedirectUri(Options.CallbackPath); } GenerateCorrelationId(properties); var redirectContext = new RedirectContext(Context, Scheme, Options, properties) { ProtocolMessage = wsFederationMessage }; await Events.RedirectToIdentityProvider(redirectContext); if (redirectContext.Handled) { return; } wsFederationMessage = redirectContext.ProtocolMessage; if (!string.IsNullOrEmpty(wsFederationMessage.Wctx)) { properties.Items[WsFederationDefaults.UserstatePropertiesKey] = wsFederationMessage.Wctx; } wsFederationMessage.Wctx = Uri.EscapeDataString(Options.StateDataFormat.Protect(properties)); var redirectUri = wsFederationMessage.CreateSignInUrl(); if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) { Logger.MalformedRedirectUri(redirectUri); } Response.Redirect(redirectUri); }
public async Task <WsFederationSigninValidationResult> ValidateAsync(WsFederationMessage message, ClaimsPrincipal user) { _logger.LogDebug("Start WsFederation signin request validator."); var validatedRequest = new ValidatedWsFederationSigninRequest { RequestMessage = message, Subject = user }; if (string.IsNullOrEmpty(message.Wa)) { _logger.LogError("Wa is missing from the request.", validatedRequest); return(new WsFederationSigninValidationResult(validatedRequest, "Missing wa", "No 'wa' was specified as part of the request.")); } if (message.Wa != WsFederationConstants.WsFederationActions.SignIn) { _logger.LogWarning("Unsupported action.", validatedRequest); return(new WsFederationSigninValidationResult(validatedRequest, "Unsupported action.", $"wa={message.Wa} is not supported.")); } if (string.IsNullOrEmpty(message.Wtrealm)) { _logger.LogError("Wtrealm is missing from the request.", validatedRequest); return(new WsFederationSigninValidationResult(validatedRequest, "Missing Wtrealm.", "Wtrealm was not passed in as a parameter.")); } var client = await _clients.FindEnabledClientByIdAsync(message.Wtrealm); if (client == null) { _logger.LogError("There is no client configured that matches the wtrealm parameter of the incoming request.", validatedRequest); return(new WsFederationSigninValidationResult(validatedRequest, "No Client.", "There is no client configured that matches the wtrealm parameter of the incoming request.")); } if (string.IsNullOrEmpty(message.Wreply)) { _logger.LogInformation("Wreply is missing from the request. Using the defualt wreply.", validatedRequest); message.Wreply = client.RedirectUris.FirstOrDefault(); } if (!client.RedirectUris.Contains(message.Wreply)) { _logger.LogError("The passed in redirect url is not valid for the given client.", validatedRequest); return(new WsFederationSigninValidationResult(validatedRequest, "Invalid redirect uri.", "The passed in redirect url is not valid for the given client.")); } validatedRequest.SetClient(client); if (validatedRequest.Client.ProtocolType != IdentityServerConstants.ProtocolTypes.WsFederation) { _logger.LogError("The client identified by the wtrealm does not support WsFederation.", validatedRequest); return(new WsFederationSigninValidationResult(validatedRequest, "Invalid protocol.", "The client identified by the wtrealm does not support WsFederation.")); } _logger.LogTrace("WsFederation signin request validation successful."); return(new WsFederationSigninValidationResult(validatedRequest)); }
public static bool AreEqual(WsFederationMessage wsFederationMessage1, WsFederationMessage wsFederationMessage2) { if (!MessageComparer.AreEqual(wsFederationMessage1 as AuthenticationProtocolMessage, wsFederationMessage2 as AuthenticationProtocolMessage)) { return(false); } return(true); }
public void ParametersTest(WsFederationMessageTheoryData theoryData) { TestUtilities.WriteHeader($"{this}.ParametersTest", theoryData); try { var wsFederationMessage = new WsFederationMessage { IssuerAddress = theoryData.IssuerAddress, Wreply = theoryData.Wreply, Wct = theoryData.Wct }; Assert.Equal(theoryData.IssuerAddress, wsFederationMessage.IssuerAddress); Assert.Equal(theoryData.Wreply, wsFederationMessage.Wreply); Assert.Equal(theoryData.Wct, wsFederationMessage.Wct); // add parameter wsFederationMessage.SetParameter(theoryData.Parameter1.Key, theoryData.Parameter1.Value); // add parameters var nameValueCollection = new NameValueCollection { { theoryData.Parameter2.Key, theoryData.Parameter2.Value }, { theoryData.Parameter3.Key, theoryData.Parameter3.Value } }; wsFederationMessage.SetParameters(nameValueCollection); // validate the parameters are added Assert.Equal(theoryData.Parameter1.Value, wsFederationMessage.Parameters[theoryData.Parameter1.Key]); Assert.Equal(theoryData.Parameter2.Value, wsFederationMessage.Parameters[theoryData.Parameter2.Key]); Assert.Equal(theoryData.Parameter3.Value, wsFederationMessage.Parameters[theoryData.Parameter3.Key]); // remove parameter wsFederationMessage.SetParameter(theoryData.Parameter1.Key, null); // validate the parameter is removed Assert.False(wsFederationMessage.Parameters.ContainsKey(theoryData.Parameter1.Key)); // create redirectUri var uriString = wsFederationMessage.BuildRedirectUrl(); Uri uri = new Uri(uriString); // convert query back to WsFederationMessage var wsFederationMessageReturned = WsFederationMessage.FromQueryString(uri.Query); // validate the parameters in the returned wsFederationMessage Assert.Equal(theoryData.Parameter2.Value, wsFederationMessageReturned.Parameters[theoryData.Parameter2.Key]); Assert.Equal(theoryData.Parameter3.Value, wsFederationMessageReturned.Parameters[theoryData.Parameter3.Key]); theoryData.ExpectedException.ProcessNoException(); } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex); } }
/// <summary> /// Handles Signout /// </summary> /// <returns></returns> public virtual async Task SignOutAsync(AuthenticationProperties?properties) { var target = ResolveTarget(Options.ForwardSignOut); if (target != null) { await Context.SignOutAsync(target, properties); return; } if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); } var wsFederationMessage = new WsFederationMessage() { IssuerAddress = _configuration.TokenEndpoint ?? string.Empty, Wtrealm = Options.Wtrealm, Wa = WsFederationConstants.WsFederationActions.SignOut, }; // Set Wreply in order: // 1. properties.Redirect // 2. Options.SignOutWreply // 3. Options.Wreply if (properties != null && !string.IsNullOrEmpty(properties.RedirectUri)) { wsFederationMessage.Wreply = BuildRedirectUriIfRelative(properties.RedirectUri); } else if (!string.IsNullOrEmpty(Options.SignOutWreply)) { wsFederationMessage.Wreply = BuildRedirectUriIfRelative(Options.SignOutWreply); } else if (!string.IsNullOrEmpty(Options.Wreply)) { wsFederationMessage.Wreply = BuildRedirectUriIfRelative(Options.Wreply); } var redirectContext = new RedirectContext(Context, Scheme, Options, properties) { ProtocolMessage = wsFederationMessage }; await Events.RedirectToIdentityProvider(redirectContext); if (!redirectContext.Handled) { var redirectUri = redirectContext.ProtocolMessage.CreateSignOutUrl(); if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) { Logger.MalformedRedirectUri(redirectUri); } Response.Redirect(redirectUri); } }
/// <summary> /// Handles Signout /// </summary> /// <returns></returns> protected override async Task ApplyResponseGrantAsync() { AuthenticationResponseRevoke signout = Helper.LookupSignOut(Options.AuthenticationType, Options.AuthenticationMode); if (signout == null) { return; } if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled); } WsFederationMessage wsFederationMessage = new WsFederationMessage() { IssuerAddress = _configuration.TokenEndpoint ?? string.Empty, Wtrealm = Options.Wtrealm, Wa = WsFederationActions.SignOut, }; // Set Wreply in order: // 1. properties.Redirect // 2. Options.SignOutWreply // 3. Options.Wreply AuthenticationProperties properties = signout.Properties; if (properties != null && !string.IsNullOrEmpty(properties.RedirectUri)) { wsFederationMessage.Wreply = properties.RedirectUri; } else if (!string.IsNullOrWhiteSpace(Options.SignOutWreply)) { wsFederationMessage.Wreply = Options.SignOutWreply; } else if (!string.IsNullOrWhiteSpace(Options.Wreply)) { wsFederationMessage.Wreply = Options.Wreply; } var notification = new RedirectToIdentityProviderNotification <WsFederationMessage, WsFederationAuthenticationOptions>(Context, Options) { ProtocolMessage = wsFederationMessage }; await Options.Notifications.RedirectToIdentityProvider(notification); if (!notification.HandledResponse) { string redirectUri = notification.ProtocolMessage.CreateSignOutUrl(); if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) { _logger.WriteWarning("The sign-out redirect URI is malformed: " + redirectUri); } Response.Redirect(redirectUri); } }
public async Task <WsFederationSignoutValidationResult> ValidateAsync(WsFederationMessage message) { _logger.LogDebug("Start WsFederation signout request validator."); var validatedRequest = new ValidatedWsFederationSignoutRequest { RequestMessage = message }; validatedRequest.SessionId = await _userSession.GetSessionIdAsync(); validatedRequest.ClientIds = await _userSession.GetClientListAsync(); IEnumerable <string> postLogoutRedirectUris; //Wtrealm is not really part of the standard for signout, but it appears that some implementations include it. //If the wtrealm is specified, respect it. Otherwise, search all of the user's known clients for the wreply. if (!string.IsNullOrEmpty(message.Wtrealm)) { _logger.LogDebug("Wtrealm was specified. Using PostLogoutRedirectUris for only that client.", validatedRequest); var client = await _clients.FindEnabledClientByIdAsync(message.Wtrealm); if (client == null) { _logger.LogError("There is no client configured that matches the wtrealm parameter of the incoming request.", validatedRequest); return(new WsFederationSignoutValidationResult(validatedRequest, "No Client.", "There is no client configured that matches the wtrealm parameter of the incoming request.")); } postLogoutRedirectUris = client.PostLogoutRedirectUris; } else { _logger.LogDebug("Wtrealm was not specified. Using PostLogoutRedirectUris for all clients that the user has authenticated with.", validatedRequest); var tasks = validatedRequest.ClientIds.Select(async c => await _clients.FindEnabledClientByIdAsync(c)).ToList(); var clients = await Task.WhenAll(tasks); postLogoutRedirectUris = clients.SelectMany(c => c.PostLogoutRedirectUris).Where(uri => !string.IsNullOrEmpty(uri)); } //This behavior might be odd. If the user is authenticated with multiple clients, it's probably bad to redirect them to a random client.... if (string.IsNullOrEmpty(message.Wreply)) { _logger.LogInformation("Wreply is missing from the request. Using the defualt wreply.", validatedRequest); validatedRequest.PostLogOutUri = postLogoutRedirectUris.FirstOrDefault(); } else if (postLogoutRedirectUris.Contains(message.Wreply)) { validatedRequest.PostLogOutUri = message.Wreply; } else { _logger.LogError("The passed in redirect url is not valid for the given client.", validatedRequest); return(new WsFederationSignoutValidationResult(validatedRequest, "Invalid redirect uri.", "The passed in redirect url is not valid for the given client.")); } _logger.LogTrace("WsFederation signout request validation successful."); return(new WsFederationSignoutValidationResult(validatedRequest)); }
public static bool AreWsFederationMessagesEqual(WsFederationMessage message1, WsFederationMessage message2, CompareContext context) { var localContext = new CompareContext(context); if (ContinueCheckingEquality(message1, message2, localContext)) { CompareAllPublicProperties(message1, message2, localContext); } return(context.Merge(localContext)); }
private WsFederationMessage GetSignInRequestMessage(string returnUrl) { var uri = new Uri("https://dummy.com" + returnUrl); WsFederationMessage message = WsFederationMessage.FromUri(uri); if (message.IsSignInMessage) { return(message); } return(null); }
private WsFederationMessage GetSignInRequestMessage(string returnUrl) { var decoded = WebUtility.UrlDecode(returnUrl); WsFederationMessage message = WsFederationMessage.FromQueryString(decoded); if (message.IsSignInMessage) { return(message); } return(null); }
public void WsFederationAuthenticationMessage_GetSets() { WsFederationMessage wsFederationMessage = new WsFederationMessage(); Type type = typeof(WsFederationParameterNames); FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static); foreach (FieldInfo fieldInfo in fields) { TestUtilities.GetSet(wsFederationMessage, fieldInfo.Name, null, new object[] { fieldInfo.Name, null, fieldInfo.Name + fieldInfo.Name }); } }
/// <summary> /// Handles Challenge /// </summary> /// <returns></returns> protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); } string baseUri = Request.Scheme + Uri.SchemeDelimiter + Request.Host + Request.PathBase; string currentUri = baseUri + Request.Path + Request.QueryString; // Save the original challenge URI so we can redirect back to it when we're done. if (string.IsNullOrEmpty(properties.RedirectUri)) { properties.RedirectUri = currentUri; } WsFederationMessage wsFederationMessage = new WsFederationMessage() { IssuerAddress = _configuration.TokenEndpoint ?? string.Empty, Wtrealm = Options.Wtrealm, Wctx = WsFederationDefaults.WctxKey + "=" + Uri.EscapeDataString(Options.StateDataFormat.Protect(properties)), Wa = WsFederationConstants.WsFederationActions.SignIn, }; if (!string.IsNullOrWhiteSpace(Options.Wreply)) { wsFederationMessage.Wreply = Options.Wreply; } var redirectContext = new RedirectContext(Context, Scheme, Options, properties) { ProtocolMessage = wsFederationMessage }; await Options.Events.RedirectToIdentityProvider(redirectContext); if (!redirectContext.Handled) { string redirectUri = redirectContext.ProtocolMessage.CreateSignInUrl(); if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) { Logger.LogWarning("The sign-in redirect URI is malformed: " + redirectUri); } Response.Redirect(redirectUri); } }
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 <IEndpointResult> ProcessAsync(HttpContext context) { _logger.LogDebug("Processing WsFederation request."); if (!HttpMethods.IsGet(context.Request.Method)) { _logger.LogWarning($"WsFederation endpoint only supports GET requests. Current method is {context.Request.Method}"); return(new StatusCodeResult(HttpStatusCode.MethodNotAllowed)); } var queryString = context.Request.QueryString; _logger.LogDebug($"Proccessing WsFederation signin request with QueryString: {queryString}."); var message = WsFederationMessage.FromQueryString(queryString.Value); var user = await _userSession.GetUserAsync(); if (message.IsSignOutMessage) { var signoutValidationResult = await _signoutValidator.ValidateAsync(message); return(new WsFederationSignoutResult(signoutValidationResult)); } else //Sign in validator also handles errors for unsupported wa { var validationResult = await _signinValidator.ValidateAsync(message, user); if (validationResult.IsError) { _logger.LogError("WsFederation Signin request validation failed."); return(new WsFederationSigninResult(new WsFederationSigninResponse { Request = validationResult.ValidatedRequest, Error = validationResult.Error, ErrorDescription = validationResult.ErrorDescription })); } //if needed, show login page if (IsLoginRequired(user, message)) { return(new WsFederationLoginPageResult(validationResult.ValidatedRequest)); } //Otherwise, return result var response = await _responseGenerator.GenerateResponseAsync(validationResult.ValidatedRequest); _logger.LogTrace("End get WsFederation signin request."); return(new WsFederationSigninResult(response)); } }
/// <summary> /// Handles Signout /// </summary> /// <returns></returns> protected override async Task ApplyResponseGrantAsync() { AuthenticationResponseRevoke signout = Helper.LookupSignOut(Options.AuthenticationType, Options.AuthenticationMode); if (signout != null) { object obj = null; Context.Environment.TryGetValue("wsfed.SignOutRedirect", out obj); string wreply = obj as string; WsFederationMessage wsFederationMessage = new WsFederationMessage() { IssuerAddress = Options.IssuerAddress ?? string.Empty, Wtrealm = Options.Wtrealm, }; if (!string.IsNullOrWhiteSpace(wreply)) { wsFederationMessage.Wreply = wreply; } else if (!string.IsNullOrWhiteSpace(Options.Wreply)) { wsFederationMessage.Wreply = Options.Wreply; } if (Options.Notifications != null && Options.Notifications.RedirectToIdentityProvider != null) { RedirectToIdentityProviderNotification <WsFederationMessage> notification = new RedirectToIdentityProviderNotification <WsFederationMessage> { ProtocolMessage = wsFederationMessage }; await Options.Notifications.RedirectToIdentityProvider(notification); if (notification.Cancel) { return; } } string redirect = wsFederationMessage.CreateSignOutQueryString(); if (!Uri.IsWellFormedUriString(redirect, UriKind.Absolute)) { _logger.WriteError(string.Format(CultureInfo.InvariantCulture, "The WsFederation sign-out redirect uri is not well formed: '{0}'", redirect)); return; } Response.Redirect(redirect); } }
public void CompareWsFederationMessages() { TestUtilities.WriteHeader($"{this}.CompareWsFederationMessages", true); var context = new CompareContext($"{this}.CompareWsFederationMessages"); var message1 = new WsFederationMessage { Wa = Guid.NewGuid().ToString() }; var message2 = new WsFederationMessage { Wa = Guid.NewGuid().ToString() }; IdentityComparer.AreEqual(message1, message2, context); Assert.True(context.Diffs.Count(s => s == "Wa:") == 1); }
public async Task WsFederation_signin_request_user_not_authenticated_redirect_to_login_page_success() { var wsMessage = new WsFederationMessage { IssuerAddress = "/wsfederation", Wtrealm = "urn:owinrp", Wreply = "http://localhost:10313/", }; var signInUrl = wsMessage.CreateSignInUrl(); var response = await _client.GetAsync(signInUrl); Assert.Equal(HttpStatusCode.Found, response.StatusCode); var expectedLocation = "/Account/Login?ReturnUrl=%2Fwsfederation%3Fwtrealm%3Durn%253Aowinrp%26wreply%3Dhttp%253A%252F%252Flocalhost%253A10313%252F%26wa%3Dwsignin1.0"; Assert.Equal(expectedLocation, response.Headers.Location.OriginalString); }
/// <summary> /// Handles Signout /// </summary> /// <returns></returns> public async virtual Task SignOutAsync(AuthenticationProperties properties) { if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); } var wsFederationMessage = new WsFederationMessage() { IssuerAddress = _configuration.TokenEndpoint ?? string.Empty, Wtrealm = Options.Wtrealm, Wa = WsFederationConstants.WsFederationActions.SignOut, }; // Set Wreply in order: // 1. properties.Redirect // 2. Options.SignOutWreply // 3. Options.Wreply if (properties != null && !string.IsNullOrEmpty(properties.RedirectUri)) { wsFederationMessage.Wreply = properties.RedirectUri; } else if (!string.IsNullOrWhiteSpace(Options.SignOutWreply)) { wsFederationMessage.Wreply = Options.SignOutWreply; } else if (!string.IsNullOrWhiteSpace(Options.Wreply)) { wsFederationMessage.Wreply = Options.Wreply; } var redirectContext = new RedirectContext(Context, Scheme, Options, properties) { ProtocolMessage = wsFederationMessage }; await Options.Events.RedirectToIdentityProvider(redirectContext); if (!redirectContext.Handled) { string redirectUri = redirectContext.ProtocolMessage.CreateSignOutUrl(); if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) { Logger.LogWarning("The sign-out redirect URI is malformed: " + redirectUri); } Response.Redirect(redirectUri); } }
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); }
private async Task <IActionResult> ProcessSignOutAsync(WsFederationMessage message) { if (string.IsNullOrWhiteSpace(message.Wreply) || string.IsNullOrWhiteSpace(message.Wtrealm)) { return(RedirectToLogOut()); } var result = await _signoutValidator.ValidateAsync(message, User); if (result.IsError) { throw new Exception(result.Error); } return(await RedirectToLogOutAsync(result)); }
public void QueryStringTest(WsFederationMessageTheoryData theoryData) { var context = TestUtilities.WriteHeader($"{this}.QueryStringTest", theoryData); try { var wsFederationMessage = WsFederationMessage.FromQueryString(theoryData.WsFederationMessageTestSet.Xml); theoryData.ExpectedException.ProcessNoException(); IdentityComparer.AreWsFederationMessagesEqual(wsFederationMessage, theoryData.WsFederationMessageTestSet.WsFederationMessage, context); } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex); } TestUtilities.AssertFailIfErrors(context); }