public static CommandResult InitiateLogout(HttpRequestData request, Uri returnUrl, IOptions options, bool terminateLocalSession) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } string idpEntityId = null; Claim sessionIndexClaim = null; if (request.User != null) { idpEntityId = request.User.FindFirst(Saml2ClaimTypes.LogoutNameIdentifier)?.Issuer; sessionIndexClaim = request.User.FindFirst(Saml2ClaimTypes.SessionIndex); } IdentityProvider idp; var knownIdp = options.IdentityProviders.TryGetValue(new EntityId(idpEntityId), out idp); options.SPOptions.Logger.WriteVerbose("Initiating logout, checking requirements for federated logout" + "\n Issuer of LogoutNameIdentifier claim (should be Idp entity id): " + idpEntityId + "\n Issuer is a known Idp: " + knownIdp + "\n Session index claim (should have a value): " + sessionIndexClaim + "\n Idp has SingleLogoutServiceUrl: " + idp?.SingleLogoutServiceUrl?.OriginalString + "\n There is a signingCertificate in SPOptions: " + (options.SPOptions.SigningServiceCertificate != null) + "\n Idp configured to DisableOutboundLogoutRequests (should be false): " + idp?.DisableOutboundLogoutRequests); CommandResult commandResult; if (idpEntityId != null && knownIdp && sessionIndexClaim != null && idp.SingleLogoutServiceUrl != null && options.SPOptions.SigningServiceCertificate != null && !idp.DisableOutboundLogoutRequests) { var logoutRequest = idp.CreateLogoutRequest(request.User); commandResult = Saml2Binding.Get(idp.SingleLogoutServiceBinding) .Bind(logoutRequest); commandResult.RelayState = logoutRequest.RelayState; commandResult.RequestState = new StoredRequestState( idp.EntityId, returnUrl, logoutRequest.Id, null); if (!options.SPOptions.Compatibility.DisableLogoutStateCookie) { commandResult.SetCookieName = StoredRequestState.CookieNameBase + logoutRequest.RelayState; } commandResult.TerminateLocalSession = terminateLocalSession; options.SPOptions.Logger.WriteInformation("Sending logout request to " + idp.EntityId.Id); } else { commandResult = new CommandResult { HttpStatusCode = HttpStatusCode.SeeOther, Location = returnUrl, TerminateLocalSession = terminateLocalSession }; options.SPOptions.Logger.WriteInformation( "Federated logout not possible, redirecting to post-logout" + (terminateLocalSession ? " and clearing local session" : "")); } return(commandResult); }
/// <summary> /// Run the command, initiating or handling the assertion consumer sequence. /// </summary> /// <param name="request">Request data.</param> /// <param name="options">Options</param> /// <returns>CommandResult</returns> public CommandResult Run(HttpRequestData request, IOptions options) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } var binding = options.Notifications.GetBinding(request); if (binding != null) { UnbindResult unbindResult = null; try { unbindResult = binding.Unbind(request, options); options.Notifications.MessageUnbound(unbindResult); var samlResponse = new Saml2Response(unbindResult.Data, request.StoredRequestState?.MessageId, options); var idpContext = GetIdpContext(unbindResult.Data, request, options); var result = ProcessResponse(options, samlResponse, request.StoredRequestState, idpContext, unbindResult.RelayState); if (request.StoredRequestState != null) { result.ClearCookieName = StoredRequestState.CookieNameBase + unbindResult.RelayState; } options.Notifications.AcsCommandResultCreated(result, samlResponse); return(result); } catch (FormatException ex) { throw new BadFormatSamlResponseException( "The SAML Response did not contain valid BASE64 encoded data.", ex); } catch (XmlException ex) { var newEx = new BadFormatSamlResponseException( "The SAML response contains incorrect XML", ex); // Add the payload to the exception if (unbindResult != null) { newEx.Data["Saml2Response"] = unbindResult.Data.OuterXml; } throw newEx; } catch (Exception ex) { if (unbindResult != null) { // Add the payload to the existing exception ex.Data["Saml2Response"] = unbindResult.Data.OuterXml; } throw; } } throw new NoSamlResponseFoundException(); }
private static CommandResult InitiateLoginToIdp(IOptions options, IDictionary <string, string> relayData, Saml2Urls urls, IdentityProvider idp, Uri returnUrl, HttpRequestData request) { var authnRequest = idp.CreateAuthenticateRequest(urls); var forceAuthnString = request.QueryString["ForceAuthn"].SingleOrDefault(); if (!string.IsNullOrWhiteSpace(forceAuthnString)) { authnRequest.ForceAuthentication = bool.Parse(forceAuthnString); } var isPassiveString = request.QueryString["IsPassive"].SingleOrDefault(); if (!string.IsNullOrWhiteSpace(isPassiveString)) { authnRequest.IsPassive = bool.Parse(isPassiveString); } options.Notifications.AuthenticationRequestCreated(authnRequest, idp, relayData); var commandResult = idp.Bind(authnRequest); commandResult.RequestState = new StoredRequestState( idp.EntityId, returnUrl, authnRequest.Id, relayData); commandResult.SetCookieSecureFlag = urls.AssertionConsumerServiceUrl.IsHttps(); commandResult.SetCookieName = StoredRequestState.CookieNameBase + authnRequest.RelayState; options.Notifications.SignInCommandResultCreated(commandResult, relayData); return(commandResult); }
/// <summary> /// Get a cached binding instance that can handle the current request. /// </summary> /// <param name="request">Current HttpRequest</param> /// <returns>A derived class instance that supports the requested binding, /// or null if no binding supports the current request.</returns> public static Saml2Binding Get(HttpRequestData request) { return(bindings.FirstOrDefault(b => b.Value.CanUnbind(request)).Value); }
/// <summary> /// Checks if the binding can extract a message out of the current /// http request. /// </summary> /// <param name="request">HttpRequest to check for message.</param> /// <returns>True if the binding supports the current request.</returns> protected internal abstract bool CanUnbind(HttpRequestData request);
/// <summary> /// Extracts a message out of the current HttpRequest. /// </summary> /// <param name="request">Current HttpRequest.</param> /// <param name="options">Options, used to look up certificate information /// in bindings that validate signatures. If set to null, the returned /// result will have TrustLevel.None.</param> /// <returns>Extracted message.</returns> public virtual UnbindResult Unbind(HttpRequestData request, IOptions options) { throw new NotImplementedException(); }