internal string SaveTokenDataToDatabase() { var tokenKey = Guid.NewGuid(); var samlXml = SamlHelpers.ConvertToString(this); var encryptedToken = SamlHelpers.Protect(samlXml, GetType().Name); SqlData.SaveEncryptedSamlToken(tokenKey, encryptedToken); return(tokenKey.ToString()); }
internal string GetReturnUrl() { string returnUrl = SamlHelpers.GetCookieReturnUrl(); SamlHelpers.ClearCookieReturnUrl(); if (string.IsNullOrEmpty(returnUrl)) { returnUrl = Apis.Get <IUrl>().Absolute(Apis.Get <ICoreUrls>().Home()); } return(returnUrl); }
internal string SaveToSecureCookie() { var tokenKey = Guid.NewGuid(); string samlXml = SamlHelpers.ConvertToString(this); var encryptedToken = SamlHelpers.Protect(samlXml, this.GetType().Name); HttpCookie cookie = new HttpCookie(tokenKey.ToString(), encryptedToken); cookie.HttpOnly = true; cookie.Secure = HttpContext.Current.Request.IsSecureConnection; CookieHelper.AddCookie(cookie); return(tokenKey.ToString()); }
internal static SamlTokenData GetFromSecureCookie(string tokenKey) { try { HttpCookie secureCookie = CookieHelper.GetCookie(tokenKey); var samlXml = SamlHelpers.Unprotect(secureCookie.Value, typeof(SamlTokenData).Name); var samlTokenData = SamlHelpers.Deserialize <SamlTokenData>(samlXml); return(samlTokenData); } catch (Exception ex) { Apis.Get <IEventLog>().Write("Error Extracting SAML token from cookie:" + ex, new EventLogEntryWriteOptions { Category = "SAML", EventType = "Error", EventId = 1001 }); } return(null); }
internal static SamlTokenData GetTokenDataFromDatabase(string tokenKey) { try { var encryptedData = SqlData.GetTokenData(tokenKey); if (!string.IsNullOrEmpty(encryptedData)) { var samlXml = SamlHelpers.Unprotect(encryptedData, typeof(SamlTokenData).Name); var samlTokenData = SamlHelpers.Deserialize <SamlTokenData>(samlXml); return(samlTokenData); } } catch (Exception ex) { ApiEventLog.Write("Error Extracting SAML token from database:" + ex, new EventLogEntryWriteOptions() { Category = "SAML", EventType = "Error", EventId = 1001 }); } return(null); }
public void ProcessRequest(HttpContext context) { string returnUrl = "/"; //protect against no httpcontext or cs context try { //exclude logout and register urls from setting the return url //grab the invitation key Guid?invitationKey = null; Guid parsedInvitationKey; //add user invitation guid if present... var i = SamlHelpers.GetInvitationKey(); if (i != null) { if (Guid.TryParse(i, out parsedInvitationKey)) { invitationKey = parsedInvitationKey; } } //note we still have the case where the invitation may be in the return url var returnUrlParam = context.Request.QueryString[SamlHelpers.ReturnUrlParameterName]; if (IsValidReturnUrl(returnUrlParam)) //ignores pages like logout or register or errors { returnUrl = context.Request[SamlHelpers.ReturnUrlParameterName]; //if there is more than one return url, just use the first returnUrl = returnUrl.Split(',')[0]; } SamlHelpers.SetCookieReturnUrl(returnUrl, invitationKey); } catch (Exception ex) { Apis.Get <IEventLog>().Write("Error Creating SAML return URL cookie:" + ex, new EventLogEntryWriteOptions { Category = "SAML", EventType = "Error", EventId = 1000 }); } var samlPlugin = PluginManager.GetSingleton <SamlOAuthClient>(); if (samlPlugin == null) { throw new InvalidOperationException("Unable to load the SamlAuthentication plugin; saml logins are not supported in the current configuration"); } var requestId = "_" + Guid.NewGuid().ToString(); var issuerUrl = Apis.Get <IUrl>().Absolute(Apis.Get <ICoreUrls>().Home()); //if (samlPlugin.IdpBindingType == SamlBinding.SAML11_POST && (samlPlugin.IdpAuthRequestType != AuthnBinding.IDP_Initiated) || (samlPlugin.IdpAuthRequestType != AuthnBinding.WSFededation)) // throw new NotSupportedException("Only bare get requests (without querystring or signature) are supported by the SAML 11 AuthN handler at this time"); switch (samlPlugin.IdpAuthRequestType) { case AuthnBinding.WSFededation: context.Response.Redirect(string.Format(WsFederationSignInTemplate, samlPlugin.IdpUrl, HttpUtility.UrlEncode(Apis.Get <IUrl>().Absolute("~/")), HttpUtility.UrlEncode(Apis.Get <IUrl>().Absolute("~/samlresponse")))); HttpContext.Current.ApplicationInstance.CompleteRequest(); break; case AuthnBinding.IDP_Initiated: context.Response.Redirect(samlPlugin.IdpUrl, false); HttpContext.Current.ApplicationInstance.CompleteRequest(); break; case AuthnBinding.Redirect: //untested context.Response.Redirect(samlPlugin.IdpUrl + "?SAMLRequest=" + HttpUtility.UrlEncode(System.Text.Encoding.Default.GetString(ZipStr(GetSamlAuthnBase64(requestId, samlPlugin.IdpUrl, issuerUrl)))) + "&RelayState=" + HttpUtility.UrlEncode("/SamlLogin?ReturnUrl=" + returnUrl), false); HttpContext.Current.ApplicationInstance.CompleteRequest(); break; case AuthnBinding.SignedRedirect: var redirectThumbprint = samlPlugin.AuthNCertThumbrint; if (string.IsNullOrEmpty(redirectThumbprint)) { throw new ArgumentNullException("Invalid configuration, the SAML Plugin is set to sign AuthN requests, but no certificate thumbprint is configured", "samlPlugin.AuthNCertThumbrint"); } throw new NotImplementedException(); //break; case AuthnBinding.POST: var authXML = GetSamlAuthnXml(requestId, samlPlugin.IdpUrl, issuerUrl); ValidateXML(authXML); POSTAuthNRequest(samlPlugin.IdpUrl, authXML); break; case AuthnBinding.SignedPOST: var postThumbprint = samlPlugin.AuthNCertThumbrint; if (string.IsNullOrEmpty(postThumbprint)) { throw new ArgumentNullException("Invalid configuration, the SAML Plugin is set to sign AuthN requests, but no certificate thumbprint is configured", "samlPlugin.AuthNCertThumbrint"); } var signedAuthXML = GetSamlAuthnXml(requestId, samlPlugin.IdpUrl, issuerUrl, postThumbprint); ValidateXML(signedAuthXML); POSTAuthNRequest(samlPlugin.IdpUrl, signedAuthXML); break; } }
public override string GetIssuerName(SecurityToken securityToken) { if (securityToken == null) { throw new ArgumentNullException("securityToken"); } X509SecurityToken token = securityToken as X509SecurityToken; if (token != null) { string thumbprint = token.Certificate.Thumbprint; if (this._configuredTrustedIssuers.ContainsKey(thumbprint)) { string str2 = this._configuredTrustedIssuers[thumbprint]; str2 = string.IsNullOrEmpty(str2) ? token.Certificate.Subject : str2; return(str2); } throw new KeyNotFoundException(string.Format("Could not find Thumbprint '{0}' in trusted issuers list : {1} :: Char Codes {2} vs {3}", thumbprint, string.Join(",", _configuredTrustedIssuers.Keys.ToArray <string>()), SamlHelpers.ToCompositeString(thumbprint), SamlHelpers.ToCompositeString(string.Join(",", _configuredTrustedIssuers.Keys.ToArray <string>())))); } //Throw our own exception to make it easier to debug throw new ArgumentException("Unable to validate token issuer the provided token was not a X509SecurityToken; cant determine the thumbprint to match", "securityToken"); }
public void ProcessRequest(HttpContext context) { var samlPlugin = PluginManager.GetSingleton <SamlOAuthClient>(); if (samlPlugin == null || !samlPlugin.Enabled) { throw new InvalidOperationException("Unable to load the SamlAuthentication plugin; saml logins are not supported in the current configuration"); } if (SamlHelpers.IsSignInResponse) { //use httpcontextuser is set to true, so this code below will only ever fire if there is a HttpContextUser set SamlTokenData samlTokenData = null; if (!SamlHelpers.IsSignInResponse) { throw new NotSupportedException("Unable to detect a saml response; please check your identity provider is configured properly"); } //This call gets the saml token from the response, validates it and turns it into our internal class for use and storage samlTokenData = samlPlugin.TokenProcessor.GetSamlTokenData(); if (samlTokenData == null) { throw new InvalidOperationException("No valid saml token was decected, login failed"); } if (samlTokenData.IsExistingUser()) { if (samlPlugin.PersistClaims) { SqlData.SaveSamlToken(samlTokenData); } //since new users will have oauth links auto created, we only run this code for existing users var samlOAuthLinkManager = PluginManager.GetSingleton <ISamlOAuthLinkManager>(); if (samlOAuthLinkManager != null && samlOAuthLinkManager.Enabled) { // makes sure the user is not prompted to "link accounts" during the login form //if there is no suitable entry in the te_OAuth_Links table samlOAuthLinkManager.EnsureOAuthLink(samlTokenData); } } //Store out the SAML Token Data in an encrypted cookie for use on the OAuth endpoint which requires a GET request //var tokenKey = samlTokenData.SaveToSecureCookie(); //Store out the SAML Token Data in a table on the database for use in the OAuth endpoint which requires a GET request //This was added to prevent issues with cookie size - Tony Triguero 2/14/2019 var tokenKey = samlTokenData.SaveTokenDataToDatabase(); //build the oauth url based on the current url UriBuilder oAuthUrl = new UriBuilder(context.Request.Url); oAuthUrl.Path = oAuthUrl.Path.Replace("samlresponse/", string.Format("oauth", samlPlugin.ClientType)).Replace("samlresponse", string.Format("oauth", samlPlugin.ClientType)); var queryString = HttpUtility.ParseQueryString(oAuthUrl.Query); queryString.Add("type", samlPlugin.ClientType); queryString.Add(SamlOAuthClient.oauthTokeyQuerystringKey, tokenKey.ToString()); //Invitation Key string invitationKey = SamlHelpers.GetInvitationKey(); if (!String.IsNullOrEmpty(invitationKey) && !queryString.ToString().ToLower().Contains("invitationkey=")) { queryString.Add(SamlHelpers.InvitationKeyParameterName, invitationKey); } //Return Url (note this must return back to the login page, the actual final return url should be double encoded) string returnUrl = GetReturnUrl(); if (!String.IsNullOrEmpty(returnUrl) && !queryString.ToString().ToLower().Contains("returnurl=")) { queryString.Add(SamlHelpers.ReturnUrlParameterName, string.Format("{0}&{1}={2}", samlPlugin.CallbackUrl, SamlHelpers.ReturnUrlParameterName, returnUrl)); //the ToString of the queryString object will properly encode the &ReturnUrl } oAuthUrl.Query = queryString.ToString(); //Ensure HTTPS so our secure cookie can be read if (samlPlugin.SecureCookie || HttpContext.Current.Request.IsSecureConnection) { oAuthUrl.Scheme = Uri.UriSchemeHttps; oAuthUrl.Port = -1; // default port for scheme } //redirect to the oauth endpoint var url = oAuthUrl.Uri.AbsoluteUri; context.Response.Redirect(oAuthUrl.Uri.AbsoluteUri); context.ApplicationInstance.CompleteRequest(); context.Response.End(); } else if (SamlHelpers.IsSignOutResponse) { var platformLogout = PluginManager.GetSingleton <IPlatformLogout>(); if (platformLogout == null || !platformLogout.Enabled) { throw new NotSupportedException("Unable to support WSFederation logouts without an appropriate IPlatformLogout plugin"); } platformLogout.Logout(); context.Response.Clear(); context.Response.Buffer = true; // Read the original file from disk Stream myFileStream = EmbeddedResources.GetStream("Telligent.Services.SamlAuthenticationPlugin.Resources.Images.oauth.gif"); long FileSize = myFileStream.Length; byte[] Buffer = new byte[(int)FileSize]; myFileStream.Read(Buffer, 0, (int)FileSize); myFileStream.Close(); // Tell the browser stuff about the file context.Response.AddHeader("Content-Length", FileSize.ToString()); context.Response.AddHeader("Content-Disposition", "inline; filename=oauth.gif"); context.Response.ContentType = "image/gif"; // Send the data to the browser context.Response.BinaryWrite(Buffer); context.ApplicationInstance.CompleteRequest(); context.Response.End(); return; } //if this is not a sign-in response, we should probably redirect to login.aspx throw new ArgumentException("The SAML token was not found in the HttpContext.Current.Request, please check the configuration and try again"); }