public async Task IsPostLogoutRedirectUriValidAsync() { (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("https://t1.api.abp.io:8080/signin-oidc", _testClient)).ShouldBeTrue(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("https://api.abp.io:8080/signin-oidc", _testClient)).ShouldBeTrue(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://t2.ng.abp.io/index.html", _testClient)).ShouldBeTrue(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://ng.abp.io/index.html", _testClient)).ShouldBeTrue(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("https://api.abp:8080/", _testClient)).ShouldBeFalse(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://ng.abp.io", _testClient)).ShouldBeTrue(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("https://api.t1.abp:8080/", _testClient)).ShouldBeFalse(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://ng.t1.abp.io", _testClient)).ShouldBeFalse(); (await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://t1.ng.abp.io/index.html.mydomain.com", _testClient)).ShouldBeFalse(); }
private async Task <IHttpActionResult> ProcessSignOutAsync(SignOutRequestMessage msg) { if (String.IsNullOrWhiteSpace(msg.Reply)) { return(RedirectToLogOut()); } if (await _redirectUriValidator.IsPostLogoutRedirectUriValidAsync(msg.Reply) == false) { const string error = "invalid_signout_reply_uri"; Logger.Error(error); return(BadRequest(error)); } return(RedirectToLogOut(msg.Reply)); }
private async Task <IHttpActionResult> ProcessSignOutAsync(SignOutRequestMessage msg) { // in order to determine redirect url wreply and wtrealm must be non-empty if (String.IsNullOrWhiteSpace(msg.Reply) || String.IsNullOrWhiteSpace(msg.GetParameter("wtrealm"))) { return(RedirectToLogOut()); } var result = await _signOutValidator.ValidateAsync(msg); if (result.IsError) { Logger.Error(result.Error); await _events.RaiseFailureWsFederationEndpointEventAsync( WsFederationEventConstants.Operations.SignOut, result.RelyingParty.Realm, User as ClaimsPrincipal, Request.RequestUri.AbsoluteUri, result.Error); return(BadRequest(result.Error)); } if (await _redirectUriValidator.IsPostLogoutRedirectUriValidAsync(msg.Reply, result.RelyingParty) == false) { const string error = "invalid_signout_reply_uri"; Logger.Error(error); await _events.RaiseFailureWsFederationEndpointEventAsync( WsFederationEventConstants.Operations.SignOut, result.RelyingParty.Realm, User as ClaimsPrincipal, Request.RequestUri.AbsoluteUri, error); return(BadRequest(error)); } await _events.RaiseSuccessfulWsFederationEndpointEventAsync( WsFederationEventConstants.Operations.SignOut, result.RelyingParty.Realm, User as ClaimsPrincipal, Request.RequestUri.AbsoluteUri); return(RedirectToLogOut(msg.Reply)); }
/// <inheritdoc /> public async Task <EndSessionValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject) { Logger.LogDebug("Start end session request validation"); var isAuthenticated = subject.IsAuthenticated(); if (!isAuthenticated && Options.Authentication.RequireAuthenticatedUserForSignOutMessage) { return(Invalid("User is anonymous. Ignoring end session parameters")); } var validatedRequest = new ValidatedEndSessionRequest { Raw = parameters }; var idTokenHint = parameters.Get(OidcConstants.EndSessionRequest.IdTokenHint); if (idTokenHint.IsPresent()) { // validate id_token - no need to validate token life time // todo: consider passing a flag to not call IsActive on the profile service? #3470 var tokenValidationResult = await TokenValidator.ValidateIdentityTokenAsync(idTokenHint, null, false); if (tokenValidationResult.IsError) { return(Invalid("Error validating id token hint", validatedRequest)); } validatedRequest.Client = tokenValidationResult.Client; // validate sub claim against currently logged on user var subClaim = tokenValidationResult.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null && isAuthenticated) { if (subject.GetSubjectId() != subClaim.Value) { // todo: consider not failing here and continue processing and check post logout redirect uri // this would mean a change to how that's validated (and not require client validated via id_token_hint) return(Invalid("Current user does not match identity token", validatedRequest)); } validatedRequest.Subject = subject; validatedRequest.SessionId = await UserSession.GetSessionIdAsync(); validatedRequest.ClientIds = await UserSession.GetClientListAsync(); } var redirectUri = parameters.Get(OidcConstants.EndSessionRequest.PostLogoutRedirectUri); if (redirectUri.IsPresent()) { if (await UriValidator.IsPostLogoutRedirectUriValidAsync(redirectUri, validatedRequest.Client)) { validatedRequest.PostLogOutUri = redirectUri; //return Invalid("Invalid post logout URI", validatedRequest); } else { Logger.LogWarning("Invalid PostLogoutRedirectUri: {postLogoutRedirectUri}", redirectUri); } } else if (validatedRequest.Client.PostLogoutRedirectUris.Count == 1) { // todo: reconsider/remove? validatedRequest.PostLogOutUri = validatedRequest.Client.PostLogoutRedirectUris.First(); } if (validatedRequest.PostLogOutUri != null) { var state = parameters.Get(OidcConstants.EndSessionRequest.State); if (state.IsPresent()) { validatedRequest.State = state; } } } else { // no id_token to authenticate the client, but we do have a user and a user session validatedRequest.Subject = subject; validatedRequest.SessionId = await UserSession.GetSessionIdAsync(); validatedRequest.ClientIds = await UserSession.GetClientListAsync(); } LogSuccess(validatedRequest); return(new EndSessionValidationResult { ValidatedRequest = validatedRequest, IsError = false }); }
public async Task <EndSessionValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject) { _logger.LogDebug("Start end session request validation"); var isAuthenticated = subject != null && subject.Identity != null && subject.Identity.IsAuthenticated; if (!isAuthenticated && _options.AuthenticationOptions.RequireAuthenticatedUserForSignOutMessage) { return(Invalid("User is anonymous. Ignoring end session parameters")); } var validatedRequest = new ValidatedEndSessionRequest() { Raw = parameters, }; var idTokenHint = parameters.Get(OidcConstants.EndSessionRequest.IdTokenHint); if (idTokenHint.IsPresent()) { // validate id_token - no need to validate token life time var tokenValidationResult = await _tokenValidator.ValidateIdentityTokenAsync(idTokenHint, null, false); if (tokenValidationResult.IsError) { return(Invalid("Error validating id token hint", validatedRequest)); } validatedRequest.Client = tokenValidationResult.Client; // validate sub claim against currently logged on user var subClaim = tokenValidationResult.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null && isAuthenticated) { if (subject.GetSubjectId() != subClaim.Value) { return(Invalid("Current user does not match identity token", validatedRequest)); } validatedRequest.Subject = subject; } var redirectUri = parameters.Get(OidcConstants.EndSessionRequest.PostLogoutRedirectUri); if (redirectUri.IsPresent()) { if (await _uriValidator.IsPostLogoutRedirectUriValidAsync(redirectUri, validatedRequest.Client) == false) { return(Invalid("Invalid post logout URI", validatedRequest)); } validatedRequest.PostLogOutUri = redirectUri; } else if (validatedRequest.Client.PostLogoutRedirectUris.Count == 1) { validatedRequest.PostLogOutUri = validatedRequest.Client.PostLogoutRedirectUris.First(); } if (validatedRequest.PostLogOutUri != null) { var state = parameters.Get(OidcConstants.EndSessionRequest.State); if (state.IsPresent()) { validatedRequest.State = state; } } } LogSuccess(validatedRequest); return(new EndSessionValidationResult() { ValidatedRequest = validatedRequest, IsError = false }); }
public async Task <ValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject) { Logger.Info("Start end session request validation"); _validatedRequest.Raw = parameters; _validatedRequest.Subject = subject; if (!subject.Identity.IsAuthenticated && _options.AuthenticationOptions.RequireAuthenticatedUserForSignOutMessage) { Logger.Warn("User is anonymous. Ignoring end session parameters"); return(Invalid()); } var uiLocales = parameters.Get(Constants.EndSessionRequest.UiLocales); if (uiLocales.IsPresent()) { _validatedRequest.UiLocales = uiLocales; } var idTokenHint = parameters.Get(Constants.EndSessionRequest.IdTokenHint); if (idTokenHint.IsPresent()) { // validate id_token - no need to validate token life time var tokenValidationResult = await _tokenValidator.ValidateIdentityTokenAsync(idTokenHint, null, false); if (tokenValidationResult.IsError) { LogError("Error validating id token hint."); return(Invalid()); } _validatedRequest.Client = tokenValidationResult.Client; // validate sub claim against currently logged on user var subClaim = tokenValidationResult.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject); if (subClaim != null && subject.Identity.IsAuthenticated) { if (subject.GetSubjectId() != subClaim.Value) { LogError("Current user does not match identity token"); return(Invalid()); } } var redirectUri = parameters.Get(Constants.EndSessionRequest.PostLogoutRedirectUri); if (redirectUri.IsPresent()) { _validatedRequest.PostLogOutUri = redirectUri; if (await _uriValidator.IsPostLogoutRedirectUriValidAsync(redirectUri, _validatedRequest.Client) == false) { LogError("Invalid post logout URI"); return(Invalid()); } var state = parameters.Get(Constants.EndSessionRequest.State); if (state.IsPresent()) { _validatedRequest.State = state; } } } LogSuccess(); return(Valid()); }
/// <inheritdoc /> public async Task <EndSessionValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject) { Logger.LogDebug("Start end session request validation"); var isAuthenticated = subject.IsAuthenticated(); if (!isAuthenticated && Options.Authentication.RequireAuthenticatedUserForSignOutMessage) { return(Invalid("User is anonymous. Ignoring end session parameters")); } var validatedRequest = new ValidatedEndSessionRequest { Raw = parameters }; var idTokenHint = parameters.Get(OidcConstants.EndSessionRequest.IdTokenHint); if (idTokenHint.IsPresent()) { // validate id_token - no need to validate token life time var tokenValidationResult = await TokenValidator.ValidateIdentityTokenAsync(idTokenHint, null, false); if (tokenValidationResult.IsError) { return(Invalid("Error validating id token hint", validatedRequest)); } validatedRequest.Client = tokenValidationResult.Client; // validate sub claim against currently logged on user var subClaim = tokenValidationResult.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null && isAuthenticated) { if (subject.GetSubjectId() != subClaim.Value) { return(Invalid("Current user does not match identity token", validatedRequest)); } validatedRequest.Subject = subject; validatedRequest.SessionId = await UserSession.GetSessionIdAsync(); validatedRequest.ClientIds = await UserSession.GetClientListAsync(); } var redirectUri = parameters.Get(OidcConstants.EndSessionRequest.PostLogoutRedirectUri); if (redirectUri.IsPresent()) { if (await UriValidator.IsPostLogoutRedirectUriValidAsync(redirectUri, validatedRequest.Client)) { validatedRequest.PostLogOutUri = redirectUri; } else { Logger.LogWarning("Invalid PostLogoutRedirectUri: {postLogoutRedirectUri}", redirectUri); } } if (validatedRequest.PostLogOutUri != null) { var state = parameters.Get(OidcConstants.EndSessionRequest.State); if (state.IsPresent()) { validatedRequest.State = state; } } } else { // no id_token to authenticate the client, but we do have a user and a user session validatedRequest.Subject = subject; validatedRequest.SessionId = await UserSession.GetSessionIdAsync(); validatedRequest.ClientIds = await UserSession.GetClientListAsync(); } // todo: need OidcConstants.EndSession.UiLocales var uilocales = parameters.Get(OidcConstants.AuthorizeRequest.UiLocales); if (uilocales.IsPresent()) { if (uilocales.Length > Options.InputLengthRestrictions.UiLocale) { var log = new EndSessionRequestValidationLog(validatedRequest); Logger.LogWarning("UI locale too long. It will be ignored." + Environment.NewLine + "{@details}", log); } else { validatedRequest.UiLocales = uilocales; } } LogSuccess(validatedRequest); return(new EndSessionValidationResult { ValidatedRequest = validatedRequest, IsError = false }); }