Skip to content
Notifications
Clear all

Help: Our custom PingFederate plugin broke after the upgrade

8 Posts
8 Users
0 Reactions
19 Views
(@devops_dad_joke)
Reputable Member
Joined: 7 months ago
Posts: 288
Topic starter   [#16894]

Alright, who else has been left holding the bag after a "routine" PingFederate upgrade? 😅 We just moved from 11.1 to 11.3 and our custom authentication plugin, which has been humming along for years, decided to take an unscheduled vacation. The server logs are... less than helpful.

The plugin is a Java `SourceAdapter` that does some minor credential enrichment. Post-upgrade, PingFederate starts up fine, but the adapter just throws a `ClassCastException` deep in its `invoke` method during authentication. The stack trace points to a core Ping class, not our code. Feels like the SDK or the classloading behavior shifted.

Here's the gist of our plugin's `getAdapterConfiguration` method (the relevant bit):

```java
@Override
public AdapterConfiguration getAdapterConfiguration() {
AdapterConfigurationBuilder adapterConfigurationBuilder = new AdapterConfigurationBuilder();
adapterConfigurationBuilder
.name("OurCustomAdapter")
.attributeContract(attributeContract)
.className(OurCustomAdapter.class.getName());
// ... more config
return adapterConfigurationBuilder.build();
}
```

We've recompiled against the new 11.3 SDK JARs, no dice. Tried isolating it in its own classloader via the plugin descriptor, same error. Starting to suspect something changed in how the plugin framework proxies our classes.

Before I spend another weekend spelunking through decompiled Ping jars, has anyone hit a similar wall? Specifically:
* Did the `AdapterConfigurationBuilder` or attribute contract serialization change subtly?
* Any known issues with custom `SourceAdapter` plugins between these versions?

I love Ping, but their upgrade path for custom plugins sometimes feels like playing Jenga in the dark. - tm



   
Quote
(@benchmark_basher)
Reputable Member
Joined: 4 months ago
Posts: 312
 

Compiling against the new SDK isn't enough. The classloading in 11.3 got more aggressive about isolation. Your plugin's JAR is probably loading its own version of a Ping class that the core runtime now provides in a different classloader.

That `ClassCastException` in `invoke` is the classic symptom: you have `com.pingidentity.somecore.SomeInterface` from your plugin's JAR, but the runtime is trying to cast it to `com.pingidentity.somecore.SomeInterface` loaded from the parent PF classloader. They're identical in source, but not to the JVM.

Strip any PingFederate SDK classes out of your plugin JAR. You need to mark them as `provided` in your Maven/Gradle build. Only your custom classes should be bundled. If you've already done that, check for transitive dependencies pulling in old SDK classes.


-- bb


   
ReplyQuote
(@devops_grunt)
Honorable Member
Joined: 6 months ago
Posts: 566
 

That's exactly it. I've had to clean up this exact mess from a previous team's plugin build. They used a fat jar with maven-shade-plugin, which bundled everything.

Even marking dependencies as `provided` can fail if your build tool's dependency graph is pulling old SDK jars from an internal repository that hasn't been updated. You need to verify the actual resolved classpath. Run `mvn dependency:tree` and grep for any pingidentity artifacts that aren't the *exact* version matching your target PF 11.3 SDK.

Sometimes the fix is adding an exclusion in your pom for every transitive ping dependency, forcing it to use the provided scope.


Automate everything. Twice.


   
ReplyQuote
(@fionah)
Reputable Member
Joined: 3 months ago
Posts: 302
 

> "Feels like the SDK or the classloading behavior shifted."

You're getting a lot of advice about classloader isolation, and sure, that's the usual suspect. But let me slow down the parade of "just exclude the transitive dependencies" replies for a second.

Recompiling against the "new SDK" -- which version exactly? The 11.3 SDK JARs Ping ships are not the same as the ones from 11.1, and they're not always backward compatible in the way the docs imply. The fact that the stack trace points to a *core Ping class* in invoke doesn't automatically mean it's a classloader conflict. Could be that the API contract of that core class actually changed between 11.1 and 11.3, and your plugin is calling a method that no longer exists, or returns a different type. The JVM will throw a ClassCastException if the method signature changed and the compiler didn't catch it because you compiled against a different version.

Have you actually looked at the bytecode or the actual method signature in the 11.3 runtime jar? Or are you just assuming recompiling is enough? I've seen people spend a week cleaning up fat jars only to find out the real problem was a renamed interface.

Also, that `getAdapterConfiguration` snippet you posted -- it's incomplete, but I notice you're calling `className(OurCustomAdapter.class.getName())`. If that class is in your plugin jar, fine. But if the core runtime changed how it loads that class, even an isolated classloader won't save you. I'd check the Ping release notes for any deprecation warnings on the `SourceAdapter` interface itself. They might have just quietly removed a method you're relying on.


trust but verify


   
ReplyQuote
(@annac)
Reputable Member
Joined: 3 months ago
Posts: 391
 

Totally right about the provided scope. That's usually the fix, but I've seen cases where the Maven `provided` scope gets ignored during certain packaging steps, especially if you're using the maven-assembly-plugin.

A quick sanity check is to use `jar tf` on your built plugin JAR and search for any `com/pingidentity/` paths. If you see them, your build isn't stripping them out, regardless of your POM settings.

Also, watch out for dependencies that themselves have compile-time dependencies on old PF SDK artifacts - those transitive deps can sneak in unless you add explicit exclusions.


Keep it simple.


   
ReplyQuote
(@carlj)
Reputable Member
Joined: 3 months ago
Posts: 351
 

user864 raises a valid, often overlooked angle. I've wasted cycles chasing classloader ghosts when the root cause was API drift. The compiler is not a reliable safety net here, especially if you're not using the exact same SDK JARs present at runtime in the PingFederate lib folder.

A practical step: use `javap -c` to compare the bytecode of the core interface your plugin implements, between the 11.1 and 11.3 SDK jars. Focus on the method signatures mentioned in the stack trace. A change in a return type from, say, `List` to `Collection` could manifest as a `ClassCastException` deep in the invocation logic.

Also, the Ping release notes sometimes bury "behavioral changes" that equate to binary incompatibility. Did anyone check the 11.2 and 11.3 notes for mentions of the `SourceAdapter` or `AdapterConfiguration` API?


Trust but verify.


   
ReplyQuote
(@devops_dad_v2)
Reputable Member
Joined: 6 months ago
Posts: 380
 

Good catch on the bytecode comparison. `javap -c` is a solid step, but I've found it's often faster to just decompile the relevant interface with a tool like CFR and diff the source directly. Sometimes the signature change is subtle, like a generic type parameter being added or removed, which won't cause a compile error but will explode at runtime.

The mention of release notes is critical. Teams often skip the "minor" version notes (11.2) where these API shifts are introduced, then hit the wall in 11.3. I'd add: check the SDK's actual `pom.xml` if Ping provides it. The transitive dependency graph there can reveal removed or upgraded artifacts that your plugin's build is still pulling in.



   
ReplyQuote
(@davidn)
Reputable Member
Joined: 3 months ago
Posts: 305
 

The provided snippet is the right place to start looking, but I'd check the `attributeContract` object specifically. If that's built using types from the old SDK, you'll get a mismatch even if the adapter class itself compiles. The builder pattern masks where the actual incompatible object is created.

I agree with the bytecode comparison advice from later posts, but you can localize the effort. Use a decompiler only on the `AdapterConfigurationBuilder` and `AttributeContract` classes from both SDK versions. A change in a factory method return type there would cause the exact error you see.


Measure twice, buy once.


   
ReplyQuote