apereo/dotnet-cas-client

Null ProxyGrantingTicket found

Closed this issue · 7 comments

Error is random and not reproducible. There are CAS logs created.
What test should be performed to check for error before calling GetProxyTicketIdFor method
casTicket = CasAuthentication.ServiceTicketManager.GetTicket(formsAuthTicket.UserData);
if (casTicket.ProxyGrantingTicket == null)
{
// How to get PGT??
//
}
Current workaround restart IIS website on the production server.
Production is using a load balancer and a single front-end server. There is no cache enabled on the Server side. IIS application pool recycles every 20 minutes.
Test Url - https://help.3ds.com/MyAppTest.aspx
Using another My Apps Service within the company to get data by proxy authentication.
Using CAS authentication URL: https://eu1-ds-iam.3dexperience.3ds.com/3DPassport/my-profile
My Apps Service to get data using PGT - https://eu1-apps.3dexperience.3ds.com/enovia/resources/AppsMngt/apps/appsForUser
Error Output -
CAS Is Authenticated: True
CAS Ticket: ST-850625-7cwPxvNTgts9coel3kZb-cas
CAS Ticket Details: [ST-850625-7cwPxvNTgts9coel3kZb-cas] NetID............. vch Proxy............. PGT IOU......... PGT............. Proxy Tickets... Origin Service.... https://betahelp.3ds.com/MyAppTest.aspx Client Address.... 10.16.8.16 Valid From........ 2/15/2021 9:08:58 AM Valid Until....... 2/15/2021 9:38:58 AM Assertion......... Principal....... vch Valid From...... 2/15/2021 9:08:58 AM Valid Until..... 1/1/0001 12:00:00 AM Attributes......
Proxy Ticket Error: System.InvalidOperationException: Unable to obtain CAS Proxy Ticket. at DotNetCasClient.CasAuthentication.LogAndThrowOperationException(String message) at DotNetCasClient.CasAuthentication.GetProxyTicketIdFor(String targetServiceUrl) at SolidWorks.Content.SWHelp.MyAppTest.Page_Load(Object sender, EventArgs e) in C:\lc\src_ds\SWHelp\MyAppTest.aspx.cs:line 202
Good Output -
CAS Is Authenticated: True
CAS Ticket: ST-5333856-349PFWBoGyMsFKeLO4RQ-cas
CAS Ticket Details: [ST-5333856-349PFWBoGyMsFKeLO4RQ-cas] NetID............. vch Proxy............. PGT IOU......... TGT-5922734-luHmcKgrqUZObhoNLEcBAcXCT70BOh6pIXnPWZl0rhaeY7T6ew-cas PGT............. PGTIOU-661059-7ChLanrXDqlOlwfOQ7vp-cas Proxy Tickets... Origin Service.... https://help.3ds.com/HelpProductsDS.aspx Client Address.... 10.16.3.169 Valid From........ 7/14/2021 10:25:51 PM Valid Until....... 7/14/2021 10:55:51 PM Assertion......... Principal....... vch Valid From...... 7/14/2021 10:25:51 PM Valid Until..... 1/1/0001 12:00:00 AM Attributes......
Proxy Ticket from GetProxyTicketIdFor received: ST-5426807-0oYXKgxxxIJ0Sh9cmuIB-cas

Error is due to ProxyGrantingTicketId being null.
proxyGrantingTicketId cannot be null
After the exception, the problem is not being able to recover after doing CasAuthentication.ClearAuthCookie(). The only way to recover is doing an IIS reset. The code works but after getting this exception not able to recover even after doing the ClearAuthCookie().

              if (iCnt > 3)
                {
                    // CasAuthentication Clearing Auth Cookie after three Refresh tries.
                    CasAuthentication.ClearAuthCookie();
                    if ((HttpContext.Current != null) && (HttpContext.Current.Session != null))
                    {
                        HttpContext.Current.Session.Clear();
                        HttpContext.Current.Session.Abandon();
                    }
                    
                }

This is from Memory dump during error on production –
We have reviewed the dumps, please find the analysis below –
This is what we’ve been seeing. The exception we are looking for seems to be on this memory dump: w3wp__DSHelp__PID__8156__Date__02_19_2021__Time_04_59_43PM__398__First Chance System.ArgumentException.dmp
In this stack we are having the exception:
0:029> kc

Call Site

00 KERNELBASE!RaiseException
01 clr!RaiseTheExceptionInternalOnly
02 clr!IL_Throw
03 DotNetCasClient!DotNetCasClient.Utils.UrlUtil.ConstructProxyTicketRequestUrl
04 DotNetCasClient!DotNetCasClient.CasAuthentication.GetProxyTicketIdFor
05 SWHelp!SolidWorks.Content.SWHelp.MyAppTest.Page_Load
06 System_Web_ni!System.Web.UI.Control.OnLoad
07 System_Web_ni!System.Web.UI.Control.d__246.MoveNext
08 System_Web_ni!System.Web.Hosting.ApplicationManager.SuspendAllApplications
09 System_Web_ni!System.Web.UI.Control.LoadRecursiveAsync
0a System_Web_ni!System.Web.UI.Page.d__523.MoveNext
0b System_Web_ni!System.Web.Hosting.ApplicationManager.SuspendAllApplications
0c System_Web_ni!System.Web.UI.Page.ProcessRequestMainAsync
0d System_Web_ni!System.Web.UI.Page.d__515.MoveNext
0e System_Web_ni!System.Web.Hosting.ApplicationManager.SuspendAllApplications
0f System_Web_ni!System.Web.UI.Page.ProcessRequestAsync
10 System_Web_ni!System.Web.UI.Page.<>c__DisplayClass554_0.b__0
11 System_Web_ni!System.Web.HttpContext.InvokeCancellableCallback
12 System_Web_ni!System.Web.UI.Page.d__554.MoveNext
13 System_Web_ni!System.Web.Hosting.ApplicationManager.SuspendAllApplications
14 System_Web_ni!System.Web.UI.Page.ProcessRequestAsync
15 System_Web_ni!System.Web.TaskAsyncHelper.BeginTask
16 App_Web_pbgxtqie!ASP.myapptest_aspx.BeginProcessRequest

0:029> !pe2
Address: 0x00000079d3dbd960
HResult: 0x80070057
Type: System.ArgumentException
Message: For proxy ticket requests, proxyGrantingTicketId cannot be null and must be specified.
Stack Trace:
SP IP Function Source

If we review the code, the exception is being thrown as the object is null
public static string ConstructProxyTicketRequestUrl(
string proxyGrantingTicketId,
string targetService)
{
CasAuthentication.Initialize();
if (string.IsNullOrEmpty(proxyGrantingTicketId))
throw new ArgumentException("For proxy ticket requests, proxyGrantingTicketId cannot be null and must be specified.");
if (string.IsNullOrEmpty(targetService))
throw new ArgumentException("For proxy ticket requests, targetService cannot be null and must be specified.");

That is being passed as a parameter on this method:

public static string GetProxyTicketIdFor(string targetServiceUrl)
{
  CommonUtils.AssertNotNullOrEmpty(targetServiceUrl, "targetServiceUrl parameter cannot be null or empty.");
  if (CasAuthentication.ServiceTicketManager == null)
    CasAuthentication.LogAndThrowConfigurationException("Proxy authentication requires a ServiceTicketManager");
  FormsAuthenticationTicket authenticationTicket = CasAuthentication.GetFormsAuthenticationTicket();
  if (authenticationTicket == null)
    CasAuthentication.LogAndThrowOperationException("The request is not authenticated (does not have a CAS Service or Proxy ticket).");
  if (string.IsNullOrEmpty(authenticationTicket.UserData))
    CasAuthentication.LogAndThrowOperationException("The request does not have a CAS Service Ticket.");
  CasAuthenticationTicket ticket = CasAuthentication.ServiceTicketManager.GetTicket(authenticationTicket.UserData);
  if (ticket == null)
    CasAuthentication.LogAndThrowOperationException("The request does not have a valid CAS Service Ticket.");
  string responseXml = (string) null;
  try
  {
    responseXml = HttpUtil.PerformHttpGet(UrlUtil.ConstructProxyTicketRequestUrl(ticket.ProxyGrantingTicket, targetServiceUrl), true)

0:029> !do2 0000007ad8fd4368
0x0000007ad8fd4368 DotNetCasClient.CasAuthenticationTicket
0008 NetId : 0000007ad8fd18f8 "vch" [3] (System.String)
0010 ServiceTicket : 0000007ad8f7a658 "ST-1713038-t4saojRRdfuziqjT1nCh-cas" [35] (System.String)
0018 ProxyGrantingTicketIou : 0000007ad8fd2678 "PGTIOU-997576-HuIaIFJ4ceczwidxbQmf-cas" [38] (System.String)
0020 ProxyGrantingTicket : NULL
0028 Proxies : 0000007ad8fd43c8 (System.Collections.Generic.List<System.String>) [Length: 0]
0030 OriginatingServiceName : 0000007ad8fd42d8 https://help.3ds.com/MyAppTest.aspx [35] (System.String)
0038 ClientHostAddress : 0000007ad8fd4338 "10.16.8.83" [10] (System.String)
0040 Assertion : 0000007ad8fd2700 (DotNetCasClient.Security.Assertion)
0048 ValidFromDate : 0000007ad8fd43b0 19/02/2021 17:59:43 (System.DateTime)
0050 ValidUntilDate : 0000007ad8fd43b8 19/02/2021 18:29:43 (System.DateTime)

Nobody has responded to this issue and it seems no commits have been made for 5 years? Is this project abandoned?

In any case, we ran into this problem, and it turns out not to be an issue with the cas client but rather the underlying .NET framework:

https://stackoverflow.com/questions/7422859/memorycache-empty-returns-null-after-being-set

It was fixed in .NET 4.5 and also evidentally backported to .NET 4 but only available by request? Our application is using .NET 4.6, but the latest precompiled cas client binary available uses .NET 2. I'm not sure how .NET works with components using mixed framework versions, but we're going to try to compile our own cas client library using .NET 4.6 and see if the problem goes away.

Stack Overflow
I have a problem with an MVC 3 application that is using the new .NET 4 System.Runtime.Caching MemoryCache. I notice that after a seemingly unpredictable time, it stops caching stuff, and acts like...

I am glad you were able to do some debugging/troubleshooting and able to figure out what the problem was.

I'm not sure what precombiled binaries you are using, but you should be using NuGet packages. The latest NuGet package for this project supports both .NET 2, 3.5 and 4.x. So if you add the NuGet package into a project that targets 4.x, then NuGet will select the binary compiled for .NET 4.x

https://www.nuget.org/packages/DotNetCasClient/

.NET client for the Apereo Central Authentication Service (CAS)

Thanks for the info. I'm playing the role of the idp admin here :), so I don't know all the details of what our windows web developers are up to. I looked at that nuget page and just saw the ".NET Framework 2.0" label at the top, but I see now if I click on the "Frameworks" tab below there are newer versions listed.

@pbhenson ah yeah, that is confusing. Microsoft and their geniuses at naming things. That first "tag" really means it's part of the .NET Standard 2.0 "collection". At some point years ago they started to group and classify multiple actual framework version together that have "compatibility".

If you care to dig into that rabbit hole look here: https://learn.microsoft.com/en-us/dotnet/standard/frameworks

Learn about target frameworks for .NET apps and libraries.

I try to avoid Windows rabbit holes as much as possible :), but our Windows devs were stalled on sorting this out so I was digging through the .NET code trying to track down the issue.

If I understand the nuget page now, it's "compatible" with a wide range of versions from 2.0 through 4.8.1, but only provides precompiled binaries for 2.0, 3.5, 4.0, and 4.5? Our local app is using 4.6 something as I understand. I've got no idea how they pulled in this dependency though.

One way or the other, either they're using an old buggy version of the framework, or a newer version has a regression and is exhibiting the same problem. Not my issue or this module's issue at this point; hopefully they'll sort things out.

Thanks again...

@pbhenson a 4.5 assembly should work in a 4.6 application. Somehow communication to them they should be using NuGet to install package/binary dependencies. Using the NuGet Package Manager built into Visual Studio, they should be able to download this specific page named "DotNetCasClient" and when the package manager installs the package it will load and reference the correct 4.5 assembly into the project.

There are a few copy cat CAS clients out there for the traditional .NET Framework (pre "core" and pre v5) so maybe they downloaded (manually) or installed someone else's unofficial version. It could also be that they downloaded on of the very old "releases" from the Releases tab on this GitHub project. Definitely have them try and start over using the NuGet route.

I know several places that are using the most recent (1.3.2) nuget package version in .NET projects targeting 4.7.2 and 4.8.x.

If possible, try and convince them to upgrade the entire project and all dependent projects to 4.8. That 4.6 they are targeting is well out of support IIRC.