/// <summary> /// Run the command, creating and returning the service provider metadata. /// </summary> /// <param name="request">Request data.</param> /// <param name="options">Options</param> /// <returns>CommandResult</returns> public virtual CommandResult Run(HttpRequestData request, IOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var urls = new Saml2Urls(request, options); var metadata = options.SPOptions.CreateMetadata(urls); options.Notifications.MetadataCreated(metadata, urls); var result = new CommandResult() { Content = metadata.ToXmlString( options.SPOptions.SigningServiceCertificate, options.SPOptions.OutboundSigningAlgorithm), ContentType = "application/samlmetadata+xml" }; var fileName = CreateFileName(options.SPOptions.EntityId.Id); result.Headers.Add("Content-Disposition", "attachment; filename=\"" + fileName + "\""); options.Notifications.MetadataCommandResultCreated(result); options.SPOptions.Logger.WriteInformation("Created metadata"); return(result); }
/// <summary> /// Run the command, creating and returning the service provider metadata. /// </summary> /// <param name="request">Request data.</param> /// <param name="options">Options</param> /// <returns>CommandResult</returns> public CommandResult Run(HttpRequestData request, IOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var urls = new Saml2Urls(request, options); var metadata = options.SPOptions.CreateMetadata(urls); options.Notifications.MetadataCreated(metadata, urls); var result = new CommandResult() { Content = metadata.ToXmlString( options.SPOptions.SigningServiceCertificate, options.SPOptions.OutboundSigningAlgorithm), ContentType = "application/samlmetadata+xml" }; options.Notifications.MetadataCommandResultCreated(result); options.SPOptions.Logger.WriteInformation("Created metadata"); return(result); }
private static CommandResult RedirectToDiscoveryService( string returnPath, SPOptions spOptions, Saml2Urls saml2Urls, IDictionary <string, string> relayData) { string returnUrl = saml2Urls.SignInUrl.OriginalString; var relayState = SecureKeyGenerator.CreateRelayState(); returnUrl += "?RelayState=" + Uri.EscapeDataString(relayState); var redirectLocation = string.Format( CultureInfo.InvariantCulture, "{0}?entityID={1}&return={2}&returnIDParam=idp", spOptions.DiscoveryServiceUrl, Uri.EscapeDataString(spOptions.EntityId.Id), Uri.EscapeDataString(returnUrl)); var requestState = new StoredRequestState( null, returnPath == null ? null : new Uri(returnPath, UriKind.RelativeOrAbsolute), null, relayData); return(new CommandResult() { HttpStatusCode = HttpStatusCode.SeeOther, Location = new Uri(redirectLocation), RequestState = requestState, SetCookieName = StoredRequestState.CookieNameBase + relayState }); }
public static CommandResult Run( EntityId idpEntityId, string returnPath, HttpRequestData request, IOptions options, IDictionary <string, string> relayData) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var urls = new Saml2Urls(request, options); IdentityProvider idp = options.Notifications.SelectIdentityProvider(idpEntityId, relayData); if (idp == null) { var idpEntityIdString = idpEntityId?.Id; if (idpEntityIdString == null) { if (options.SPOptions.DiscoveryServiceUrl != null) { var commandResult = RedirectToDiscoveryService(returnPath, options.SPOptions, urls, relayData); options.Notifications.SignInCommandResultCreated(commandResult, relayData); options.SPOptions.Logger.WriteInformation("Redirecting to Discovery Service to select Idp."); return(commandResult); } idp = options.IdentityProviders.Default; options.SPOptions.Logger.WriteVerbose( "No specific idp requested and no Discovery Service configured. " + "Falling back to use configured default Idp " + idp.EntityId.Id); } else { if (!options.IdentityProviders.TryGetValue(idpEntityId, out idp)) { throw new InvalidOperationException("Unknown idp " + idpEntityIdString); } } } /*var returnUrl = string.IsNullOrEmpty(returnPath) * ? null * : new Uri(returnPath, UriKind.RelativeOrAbsolute);*/ var returnUrl = request.QueryString["returnUrl"].FirstOrDefault(); var errorUrl = request.QueryString["errorUrl"].FirstOrDefault(); var unauthorizedUrl = request.QueryString["unauthorizedUrl"].FirstOrDefault(); // some hacks var returnUri = new Uri($"{options.SPOptions.ReturnUrl.GetLeftPart(UriPartial.Path)}?returnUrl={returnUrl}&errorUrl={errorUrl}&unauthorizedUrl={unauthorizedUrl}"); options.SPOptions.Logger.WriteInformation("Initiating login to " + idp.EntityId.Id); return(InitiateLoginToIdp(options, relayData, urls, idp, returnUri)); }
public static CommandResult Run( EntityId idpEntityId, string returnPath, HttpRequestData request, IOptions options, IDictionary <string, string> relayData) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var urls = new Saml2Urls(request, options); if (!string.IsNullOrEmpty(returnPath)) { returnPath = options.Notifications.RewriteRedirectUrl(new Uri(returnPath, UriKind.RelativeOrAbsolute), urls.ApplicationUrl).ToString(); } IdentityProvider idp = options.Notifications.SelectIdentityProvider(idpEntityId, relayData); if (idp == null) { var idpEntityIdString = idpEntityId?.Id; if (idpEntityIdString == null) { if (options.SPOptions.DiscoveryServiceUrl != null) { var commandResult = RedirectToDiscoveryService(returnPath, options.SPOptions, urls, relayData); options.Notifications.SignInCommandResultCreated(commandResult, relayData); options.SPOptions.Logger.WriteInformation("Redirecting to Discovery Service to select Idp."); return(commandResult); } idp = options.IdentityProviders.Default; options.SPOptions.Logger.WriteVerbose( "No specific idp requested and no Discovery Service configured. " + "Falling back to use configured default Idp " + idp.EntityId.Id); } else { if (!options.IdentityProviders.TryGetValue(idpEntityId, out idp)) { throw new InvalidOperationException("Unknown idp " + idpEntityIdString); } } } var returnUrl = string.IsNullOrEmpty(returnPath) ? null : new Uri(returnPath, UriKind.RelativeOrAbsolute); options.SPOptions.Logger.WriteInformation("Initiating login to " + idp.EntityId.Id); return(InitiateLoginToIdp(options, relayData, urls, idp, returnUrl)); }
public static CommandResult Run( HttpRequestData request, string returnPath, IOptions options) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } CommandResult commandResult; var returnUrl = GetReturnUrl(request, returnPath, options); var binding = options.Notifications.GetBinding(request); if (binding != null) { var unbindResult = binding.Unbind(request, options); options.Notifications.MessageUnbound(unbindResult); switch (unbindResult.Data.LocalName) { case "LogoutRequest": VerifyMessageIsSigned(unbindResult, options); commandResult = HandleRequest(unbindResult, request, options); break; case "LogoutResponse": if (!options.SPOptions.Compatibility.AcceptUnsignedLogoutResponses) { VerifyMessageIsSigned(unbindResult, options); } var storedRequestState = options.Notifications.GetLogoutResponseState(request); var urls = new Saml2Urls(request, options); commandResult = HandleResponse(unbindResult, storedRequestState, options, returnUrl, urls); break; default: throw new NotImplementedException(); } } else { commandResult = InitiateLogout(request, returnUrl, options, true); } options.Notifications.LogoutCommandResultCreated(commandResult); return(commandResult); }
private static CommandResult InitiateLoginToIdp(IOptions options, IDictionary <string, string> relayData, Saml2Urls urls, IdentityProvider idp, Uri returnUrl) { var authnRequest = idp.CreateAuthenticateRequest(urls); options.Notifications.AuthenticationRequestCreated(authnRequest, idp, relayData); var commandResult = idp.Bind(authnRequest); commandResult.RequestState = new StoredRequestState( idp.EntityId, returnUrl, authnRequest.Id, relayData); commandResult.SetCookieName = StoredRequestState.CookieNameBase + authnRequest.RelayState; options.Notifications.SignInCommandResultCreated(commandResult, relayData); return(commandResult); }
private static CommandResult HandleResponse( UnbindResult unbindResult, StoredRequestState storedRequestState, IOptions options, Uri returnUrl, Saml2Urls urls) { var logoutResponse = Saml2LogoutResponse.FromXml(unbindResult.Data); var notificationHandledTheStatus = options.Notifications.ProcessSingleLogoutResponseStatus(logoutResponse, storedRequestState); if (!notificationHandledTheStatus) { var status = logoutResponse.Status; if (status != Saml2StatusCode.Success) { throw new UnsuccessfulSamlOperationException(string.Format(CultureInfo.InvariantCulture, "Idp returned status \"{0}\", indicating that the single logout failed. The local session has been successfully terminated.", status)); } } var commandResult = new CommandResult { HttpStatusCode = HttpStatusCode.SeeOther }; if (!options.SPOptions.Compatibility.DisableLogoutStateCookie) { commandResult.ClearCookieName = StoredRequestState.CookieNameBase + unbindResult.RelayState; commandResult.SetCookieSecureFlag = urls.LogoutUrl.IsHttps(); } commandResult.Location = storedRequestState?.ReturnUrl ?? returnUrl; options.SPOptions.Logger.WriteInformation("Received logout response " + logoutResponse.Id + ", redirecting to " + commandResult.Location); return(commandResult); }
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); } var knownIdp = options.IdentityProviders.TryGetValue(new EntityId(idpEntityId), out IdentityProvider 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); options.Notifications.LogoutRequestCreated(logoutRequest, request.User, idp); commandResult = Saml2Binding.Get(idp.SingleLogoutServiceBinding) .Bind(logoutRequest, options.SPOptions.Logger, options.Notifications.LogoutRequestXmlCreated); 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; var urls = new Saml2Urls(request, options); commandResult.SetCookieSecureFlag = urls.LogoutUrl.IsHttps(); } 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); }
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> /// 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) { var urls = new Saml2Urls(request, options); result.ClearCookieName = StoredRequestState.CookieNameBase + unbindResult.RelayState; result.SetCookieSecureFlag = urls.AssertionConsumerServiceUrl.IsHttps(); } 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(); }