/// <summary> /// Action performed during login. /// </summary> /// <param name="handler">The handler initiating the call.</param> /// <param name="context">The current http context.</param> /// <param name="assertion">The saml assertion of the currently logged in user.</param> public void LoginAction(AbstractEndpointHandler handler, SamlHttpContext context, Saml20Assertion assertion) { string idpKey = Saml20PrincipalCache.GetSaml20AssertionLite().Issuer; Saml20SignonHandler h = (Saml20SignonHandler)handler; IDPEndPoint ep = h.RetrieveIDPConfiguration(idpKey); if (ep.CDC.ExtraSettings != null) { List <KeyValue> values = ep.CDC.ExtraSettings.KeyValues; KeyValue idpEndpoint = values.Find(delegate(KeyValue kv) { return(kv.Key == IDPCookieWriterEndPoint); }); if (idpEndpoint == null) { throw new Saml20Exception(@"Please specify """ + IDPCookieWriterEndPoint + @""" in Settings element."); } KeyValue localReturnPoint = values.Find(delegate(KeyValue kv) { return(kv.Key == LocalReturnUrl); }); if (localReturnPoint == null) { throw new Saml20Exception(@"Please specify """ + LocalReturnUrl + @""" in Settings element."); } string url = idpEndpoint.Value + "?" + TargetResource + "=" + localReturnPoint.Value; context.Response.Redirect(url); } else { handler.DoRedirect(context); } }
private void HandleArtifact(SamlHttpContext context) { HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context); Stream inputStream = builder.ResolveArtifact(); HandleSOAP(context, inputStream); }
/// <summary> /// Decrypts an encrypted assertion, and sends the result to the HandleAssertion method. /// </summary> private void HandleEncryptedAssertion(SamlHttpContext context, XmlElement elem) { Trace.TraceMethodCalled(GetType(), "HandleEncryptedAssertion()"); Saml20EncryptedAssertion decryptedAssertion = GetDecryptedAssertion(elem); HandleAssertion(context, decryptedAssertion.Assertion.DocumentElement); }
/// <summary> /// Action performed during logout. /// </summary> /// <param name="handler">The handler.</param> /// <param name="context">The context.</param> /// <param name="IdPInitiated">During IdP initiated logout some actions such as redirecting should not be performed</param> public void LogoutAction(AbstractEndpointHandler handler, SamlHttpContext context, bool IdPInitiated) { if (!IdPInitiated) { handler.DoRedirect(context); } }
/// <summary> /// Displays an error page. /// </summary> /// <param name="context">The current HTTP context.</param> /// <param name="errorMessage">The error message.</param> /// <param name="overrideConfigSetting">if set to <c>true</c> [override config setting].</param> public void HandleError(SamlHttpContext context, string errorMessage, bool overrideConfigSetting) { Boolean showError = SAML20FederationConfig.GetConfig().ShowError; String DEFAULT_MESSAGE = "Unable to validate SAML message!"; if (!string.IsNullOrEmpty(ErrorBehaviour) && ErrorBehaviour.Equals(dk.nita.saml20.config.ErrorBehaviour.THROWEXCEPTION.ToString())) { if (showError) { throw new Saml20Exception(errorMessage); } else { throw new Saml20Exception(DEFAULT_MESSAGE); } } else { throw new SamlException(errorMessage); } //{ // ErrorPage page = new ErrorPage(); // page.OverrideConfig = overrideConfigSetting; // page.ErrorText = (showError) ? errorMessage : DEFAULT_MESSAGE; // page.ProcessRequest(context); // context.Response.End(); //} }
/// <summary> /// Send an authentication request to the IDP. /// </summary> private void SendRequest(SamlHttpContext context) { Trace.TraceMethodCalled(GetType(), "SendRequest()"); // See if the "ReturnUrl" - parameter is set. string returnUrl = context.Request.QueryString["ReturnUrl"]; // If PreventOpenRedirectAttack has been enabled ... the return URL is only set if the URL is local. if (!string.IsNullOrEmpty(returnUrl) && (!FederationConfig.GetConfig().PreventOpenRedirectAttack || IsLocalUrl(returnUrl))) { SessionFactory.SessionContext.Current[SessionConstants.RedirectUrl] = returnUrl; } IDPEndPoint idpEndpoint = RetrieveIDP(context); if (idpEndpoint == null) { throw new NoIdentityProviderException(); } //{ // //Display a page to the user where she can pick the IDP // SelectSaml20IDP page = new SelectSaml20IDP(); // page.ProcessRequest(context); // return; //} Saml20AuthnRequest authnRequest = Saml20AuthnRequest.GetDefault(); TransferClient(idpEndpoint, authnRequest, context); }
/// <summary> /// Handles a request. /// </summary> /// <param name="context">The context.</param> protected override void Handle(SamlHttpContext context) { Trace.TraceMethodCalled(GetType(), "Handle()"); try { //Some IdP's are known to fail to set an actual value in the SOAPAction header //so we just check for the existence of the header field. if (Array.Exists(context.Request.Headers.AllKeys, delegate(string s) { return(s == SOAPConstants.SOAPAction); })) { HandleSOAP(context, context.Request.InputStream); return; } if (!string.IsNullOrEmpty(context.Request.Params["SAMLart"])) { HandleArtifact(context); return; } if (!string.IsNullOrEmpty(context.Request.Params["SAMLResponse"])) { HandleResponse(context); } else if (!string.IsNullOrEmpty(context.Request.Params["SAMLRequest"])) { HandleRequest(context); } else { IDPEndPoint idpEndpoint = null; Saml20AssertionLite saml20AssertionLite = Saml20PrincipalCache.GetSaml20AssertionLite(); if (saml20AssertionLite != null) { idpEndpoint = RetrieveIDPConfiguration(saml20AssertionLite.Issuer); } if (idpEndpoint == null) { context.Logout(); //FormsAuthentication.SignOut(); HandleError(context, Resources.UnknownLoginIDP); } TransferClient(idpEndpoint, context); } } catch (Exception e) { //ThreadAbortException is thrown by response.Redirect so don't worry about it if (e is ThreadAbortException) { throw; } HandleError(context, e.Message); } }
private void CreateMetadataDocument(SamlHttpContext context, bool sign) { SAML20FederationConfig configuration = SAML20FederationConfig.GetConfig(); KeyInfo keyinfo = new KeyInfo(); KeyInfoX509Data keyClause = new KeyInfoX509Data(FederationConfig.GetConfig().SigningCertificate.GetCertificate(), X509IncludeOption.EndCertOnly); keyinfo.AddClause(keyClause); Saml20MetadataDocument doc = new Saml20MetadataDocument(configuration, keyinfo, sign); context.Response.Write(doc.ToXml(context.Response.ContentEncoding)); }
/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.SamlContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public sealed override void ProcessRequest(SamlHttpContext context) { Trace.TraceData(TraceEventType.Information, "ProcessRequest " + GetType().FullName); try { CheckConfiguration(context); Handle(context); } catch (Exception ex) { HandleError(context, ex); } }
private void CheckConditions(SamlHttpContext context, Saml20Assertion assertion) { if (assertion.IsOneTimeUse) { if (context.Cache[assertion.Id] != null) { HandleError(context, Resources.OneTimeUseReplay); } else { context.Cache.Insert(assertion.Id, string.Empty, null, assertion.NotOnOrAfter, SamlCache.NoSlidingExpiration); } } }
/// <summary> /// Checks the configuration elements and redirects to an error page if something is missing or wrong. /// </summary> /// <param name="ctx"></param> private void CheckConfiguration(SamlHttpContext ctx) { if (validated) { return; } string errorMessage; validated = BindingUtility.ValidateConfiguration(out errorMessage); if (!validated) { HandleError(ctx, errorMessage); } }
/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.SamlContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public override void ProcessRequest(SamlHttpContext context) { try { Trace.TraceMethodCalled(GetType(), "ProcessRequest()"); SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); if (config == null) { throw new Saml20Exception("Missing SAML20Federation config section in web.config."); } Saml20ServiceEndpoint endp = config.ServiceProvider.serviceEndpoints.Find(delegate(Saml20ServiceEndpoint ep) { return(ep.endpointType == EndpointType.SIGNON); }); if (endp == null) { throw new Saml20Exception("Signon endpoint not found in configuration"); } string returnUrl = config.ServiceProvider.Server + endp.localPath + "?r=1"; SamlHttpCookie samlIdp = context.Request.Cookies[CommonDomainCookie.COMMON_DOMAIN_COOKIE_NAME]; if (samlIdp != null) { returnUrl += "&_saml_idp=" + HttpUtility.UrlEncode(samlIdp.Value); if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.CDC, samlIdp.Value)); } AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT, "Redirection to Signon endpoint found in Common Domain Cookie: " + samlIdp.Value); } else { AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT, "Redirection to Signon endpoint, no Common Domain Cookie found: " + returnUrl); } context.Response.Redirect(returnUrl); } catch (Exception ex) { HandleError(context, ex); } }
private static void CheckReplayAttack(SamlHttpContext context, string inResponseTo) { //var expectedInResponseToSessionState = SessionFactory.SessionContext.Current[SessionConstants.ExpectedInResponseTo]; //if (expectedInResponseToSessionState == null) // throw new Saml20Exception("Your session has been disconnected, please logon again"); //string expectedInResponseTo = expectedInResponseToSessionState.ToString(); //if (string.IsNullOrEmpty(expectedInResponseTo) || string.IsNullOrEmpty(inResponseTo)) // throw new Saml20Exception("Empty protocol message id is not allowed."); //if (inResponseTo != expectedInResponseTo) //{ // AuditLogging.logEntry(Direction.IN, Operation.LOGIN, string.Format("Unexpected value {0} for InResponseTo, expected {1}, possible replay attack!", inResponseTo, expectedInResponseTo)); // throw new Saml20Exception("Replay attack."); //} }
/// <summary> /// Is called before the assertion is made into a strongly typed representation /// </summary> /// <param name="context">The SamlContext.</param> /// <param name="elem">The assertion element.</param> /// <param name="endpoint">The endpoint.</param> protected virtual void PreHandleAssertion(SamlHttpContext context, XmlElement elem, IDPEndPoint endpoint) { Trace.TraceMethodCalled(GetType(), "PreHandleAssertion"); if (endpoint != null && endpoint.SLOEndpoint != null && !String.IsNullOrEmpty(endpoint.SLOEndpoint.IdpTokenAccessor)) { ISaml20IdpTokenAccessor idpTokenAccessor = Activator.CreateInstance(Type.GetType(endpoint.SLOEndpoint.IdpTokenAccessor, false)) as ISaml20IdpTokenAccessor; if (idpTokenAccessor != null) { idpTokenAccessor.ReadToken(elem); } } Trace.TraceMethodDone(GetType(), "PreHandleAssertion"); }
private static XmlDocument GetDecodedSamlResponse(SamlHttpContext context, Encoding encoding) { string base64 = context.Request.Params["SAMLResponse"]; XmlDocument doc = new XmlDocument(); doc.XmlResolver = null; doc.PreserveWhitespace = true; string samlResponse = encoding.GetString(Convert.FromBase64String(base64)); if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, "Decoded SAMLResponse", samlResponse); } doc.LoadXml(samlResponse); return(doc); }
/// <summary> /// Displays an error page. /// </summary> /// <param name="context">The current HTTP context.</param> /// <param name="e">The exception that caused the error.</param> public void HandleError(SamlHttpContext context, Exception e) { // ThreadAbortException is just part of ASP.NET's slightly broken conditional logic, so don't react to it. if (e is ThreadAbortException) { return; } StringBuilder sb = new StringBuilder(1000); while (e != null) { sb.AppendLine(e.ToString()); e = e.InnerException; } HandleError(context, sb.ToString()); }
/// <summary> /// Redirects the user. /// </summary> /// <param name="context">The context.</param> public void DoRedirect(SamlHttpContext context) { ISession currentSession = SessionFactory.SessionContext.Current; if (currentSession != null) { var redirectUrl = (string)currentSession[SessionConstants.RedirectUrl]; if (!string.IsNullOrEmpty(redirectUrl)) { currentSession.Remove(SessionConstants.RedirectUrl); context.Response.Redirect(redirectUrl); return; } } // Use default redirect url context.Response.Redirect(string.IsNullOrEmpty(RedirectUrl) ? "~/" : RedirectUrl); }
/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.SamlContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public override void ProcessRequest(SamlHttpContext context) { try { Trace.TraceMethodCalled(GetType(), "ProcessRequest()"); SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); if (config == null) { throw new Saml20Exception("Missing SAML20Federation config section in web.config."); } Saml20ServiceEndpoint endp = config.ServiceProvider.serviceEndpoints.Find(delegate(Saml20ServiceEndpoint ep) { return(ep.endpointType == EndpointType.SIGNON); }); if (endp == null) { throw new Saml20Exception("Signon endpoint not found in configuration"); } string redirectUrl = (string)SessionFactory.SessionContext.Current[SessionConstants.RedirectUrl]; if (!string.IsNullOrEmpty(redirectUrl)) { SessionFactory.SessionContext.Current.Remove(SessionConstants.RedirectUrl); context.Response.Redirect(redirectUrl); } else if (string.IsNullOrEmpty(endp.RedirectUrl)) { context.Response.Redirect("~/"); } else { context.Response.Redirect(endp.RedirectUrl); } } catch (Exception ex) { HandleError(context, ex); } }
private void DoSoapLogout(SamlHttpContext context, string userId) { try { foreach (IAction action in Actions.Actions.GetActions()) { Trace.TraceMethodCalled(action.GetType(), "SoapLogoutAction()"); action.SoapLogoutAction(this, context, userId); Trace.TraceMethodDone(action.GetType(), "SoapLogoutAction()"); } } finally { // Always end with abandoning the session. Trace.TraceData(TraceEventType.Information, "Clearing all sessions related to user with id: " + userId); SessionFactory.SessionContext.AbandonAllSessions(userId); Trace.TraceData(TraceEventType.Verbose, "Sessions cleared."); } }
/// <summary> /// Handles a request. /// </summary> /// <param name="context">The context.</param> protected override void Handle(SamlHttpContext context) { Trace.TraceMethodCalled(GetType(), "Handle()"); //Some IdP's are known to fail to set an actual value in the SOAPAction header //so we just check for the existence of the header field. if (Array.Exists(context.Request.Headers.AllKeys, delegate(string s) { return(s == SOAPConstants.SOAPAction); })) { HandleSOAP(context, context.Request.InputStream); return; } if (!string.IsNullOrEmpty(context.Request.Params["SAMLart"])) { HandleArtifact(context); } if (!string.IsNullOrEmpty(context.Request.Params["SamlResponse"])) { HandleResponse(context); } else { if (SAML20FederationConfig.GetConfig().CommonDomain.Enabled&& context.Request.QueryString["r"] == null && context.Request.Params["cidp"] == null) { AuditLogging.logEntry(Direction.OUT, Operation.DISCOVER, "Redirecting to Common Domain for IDP discovery"); context.Response.Redirect(SAML20FederationConfig.GetConfig().CommonDomain.LocalReaderEndpoint); } else { AuditLogging.logEntry(Direction.IN, Operation.ACCESS, "User accessing resource: " + context.Request.RawUrl + " without authentication."); SendRequest(context); } } }
/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.SamlContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public override void ProcessRequest(SamlHttpContext context) { string encoding = context.Request.QueryString["encoding"]; try { if (!string.IsNullOrEmpty(encoding)) { context.Response.ContentEncoding = Encoding.GetEncoding(encoding); } } catch (ArgumentException) { HandleError(context, ResourcesEx.UnknownEncodingFormat(encoding)); return; } bool sign = true; try { string param = context.Request.QueryString["sign"]; if (!string.IsNullOrEmpty(param)) { sign = Convert.ToBoolean(param); } } catch (FormatException) { HandleError(context, Resources.GenericError); return; } context.Response.ContentType = Saml20Constants.METADATA_MIMETYPE; context.Response.AddHeader("Content-Disposition", "attachment; filename=\"metadata.xml\""); CreateMetadataDocument(context, sign); context.Response.End(); }
private void DoLogout(SamlHttpContext context, bool IdPInitiated) { try { foreach (IAction action in Actions.Actions.GetActions()) { Trace.TraceMethodCalled(action.GetType(), "LogoutAction()"); action.LogoutAction(this, context, IdPInitiated); Trace.TraceMethodDone(action.GetType(), "LogoutAction()"); } } finally { // Always end with abandoning the session. Trace.TraceData(TraceEventType.Information, "Clearing session with id: " + SessionFactory.SessionContext.Current.Id); SessionFactory.SessionContext.AbandonAllSessions(Saml20Identity.Current.Name); //SessionFactory.SessionContext.AbandonCurrentSession(); Trace.TraceData(TraceEventType.Verbose, "Session cleared."); } }
/// <summary> /// Utility function for error handling. /// </summary> /// <param name="context">The context.</param> /// <param name="status">The status.</param> protected void HandleError(SamlHttpContext context, Status status) { string errorMessage = string.Format("ErrorCode: {0}. Message: {1}.", status.StatusCode.Value, status.StatusMessage); if (status.StatusCode.SubStatusCode != null) { switch (status.StatusCode.SubStatusCode.Value) { case Saml20Constants.StatusCodes.AuthnFailed: HandleError(context, errorMessage, true); break; default: HandleError(context, errorMessage, false); break; } } else { HandleError(context, errorMessage, false); } }
private void DoLogin(SamlHttpContext context, Saml20Assertion assertion) { SessionFactory.SessionContext.AssociateUserIdWithCurrentSession(assertion.Subject.Value); SessionFactory.SessionContext.Current[SessionConstants.Saml20AssertionLite] = Saml20AssertionLite.ToLite(assertion); if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.Login, assertion.Subject.Value, assertion.SessionIndex, assertion.Subject.Format)); } string assuranceLevel = GetAssuranceLevel(assertion) ?? "(Unknown)"; AuditLogging.logEntry(Direction.IN, Operation.LOGIN, string.Format("Subject: {0} NameIDFormat: {1} Level of authentication: {2} Session timeout in minutes: {3}", assertion.Subject.Value, assertion.Subject.Format, assuranceLevel, FederationConfig.GetConfig().SessionTimeout)); foreach (IAction action in Actions.Actions.GetActions()) { Trace.TraceMethodCalled(action.GetType(), "LoginAction()"); action.LoginAction(this, context, assertion); Trace.TraceMethodDone(action.GetType(), "LoginAction()"); } }
/// <summary> /// <see cref="IAction.SoapLogoutAction"/> /// </summary> public void SoapLogoutAction(AbstractEndpointHandler handler, SamlHttpContext context, string userId) { // Do nothing }
/// <summary> /// Action performed during logout. /// </summary> /// <param name="handler">The handler.</param> /// <param name="context">The context.</param> /// <param name="IdPInitiated">During IdP initiated logout some actions such as redirecting should not be performed</param> public void LogoutAction(AbstractEndpointHandler handler, SamlHttpContext context, bool IdPInitiated) { FormsAuthentication.SignOut(); context.Logout(); }
/// <summary> /// Action performed during login. /// </summary> /// <param name="handler">The handler initiating the call.</param> /// <param name="context">The current http context.</param> /// <param name="assertion">The saml assertion of the currently logged in user.</param> public void LoginAction(AbstractEndpointHandler handler, SamlHttpContext context, Saml20Assertion assertion) { FormsAuthentication.SetAuthCookie(Saml20PrincipalCache.GetPrincipal().Identity.Name, false); }
/// <summary> /// Initializes a new instance of the <see cref="HttpArtifactBindingBuilder"/> class. /// </summary> /// <param name="context">The current http context.</param> public HttpArtifactBindingBuilder(SamlHttpContext context) : base(context) { }
/// <summary> /// Initializes a new instance of the <see cref="HttpSOAPBindingBuilder"/> class. /// </summary> /// <param name="context">The current HTTP context.</param> public HttpSOAPBindingBuilder(SamlHttpContext context) { _context = context; }
/// <summary> /// Initializes a new instance of the <see cref="HttpPostBindingParser"/> class. /// </summary> /// <param name="context">The current HTTP context.</param> public HttpPostBindingParser(SamlHttpContext context) { _context = context; Initialize(); }