java

orestis 2021-01-07T14:25:21.001200Z

I’m having Java issues with Microsoft authentication library https://github.com/AzureAD/microsoft-authentication-library-for-java I’m starting from this code:

IClientCredential credential = ClientCredentialFactory.createFromSecret(CLIENT_SECRET);
ConfidentialClientApplication app = 
    ConfidentialClientApplication
        .builder(PUBLIC_CLIENT_ID, credential)
        .authority(AUTHORITY)
        .build();
I have translated this to
(let [credential (ClientCredentialFactory/createFromSecret secret-value)
      builder ^ConfidentialClientApplication$Builder
      (ConfidentialClientApplication/builder client-id credential)]
  (->
    builder
    (.authority authority)
    (.build)))
But I’m getting this exception:
; (err) Execution error (IllegalArgumentException) at nosco.azure/eval85548 (REPL:35).
; (err) No matching method authority found taking 1 args for class com.microsoft.aad.msal4j.ConfidentialClientApplication$Builder

orestis 2021-01-07T14:26:11.002Z

I can see that authority method in the https://javadoc.io/static/com.microsoft.azure/msal4j/1.8.1/com/microsoft/aad/msal4j/ConfidentialClientApplication.Builder.html#authority-java.lang.String- but on using the clojure reflect facilities it doesn’t show…

orestis 2021-01-07T14:31:28.002500Z

Turning on reflection warnings says:

call to method authority on com.microsoft.aad.msal4j.ConfidentialClientApplication$Builder can't be resolved (argument types: java.lang.String).

orestis 2021-01-07T15:17:50.003200Z

Hm, here’s the culprit: https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/dev/src/main/java/com/microsoft/aad/msal4j/AbstractClientApplicationBase.java some fancy annotations from something called Lombok

alexmiller 2021-01-07T15:18:32.003500Z

Lombok .... rolls eyes

orestis 2021-01-07T15:19:13.004400Z

Well at least they had the source available... saved me another day of fumbling in the dark.

orestis 2021-01-07T15:19:52.005500Z

@alexmiller I take it it’s a known thing? Can I brute force my way around it? I just want to do a PoC this time round.

orestis 2021-01-07T15:20:41.006900Z

This looks to be a thick layer on top of some http apis anyway so I might just go underneath eventually but I was hoping for a quick demo.

alexmiller 2021-01-07T15:24:12.007400Z

Lombok is all about pretending Java was less cumbersome to use

alexmiller 2021-01-07T15:24:40.007800Z

by giving you alternate syntax (hey, just use Clojure!) :)

alexmiller 2021-01-07T15:24:54.008200Z

but it may be obscuring what the actual method looks like

alexmiller 2021-01-07T15:25:43.008500Z

is the real method maybe getAuthority()?

alexmiller 2021-01-07T15:26:04.008800Z

or setAuthority() ?

orestis 2021-01-07T15:26:50.009600Z

(->
  (r/reflect ConfidentialClientApplication$Builder)
  :members
  (->> (map :name)))

alexmiller 2021-01-07T15:26:55.009800Z

might be useful to use the reflection API directly and see what the actual methods are (or use clojure.reflect/reflect)

orestis 2021-01-07T15:27:01.010100Z

(com.microsoft.aad.msal4j.ConfidentialClientApplication$Builder
 build
 access$000
 com.microsoft.aad.msal4j.ConfidentialClientApplication$Builder
 build
 clientCredential
 self
 sendX5c
 self
 access$100
 sendX5c)

orestis 2021-01-07T15:27:32.010800Z

This is what I found confusing, I tried the reflection at first but this is the names of the members…

alexmiller 2021-01-07T15:27:44.011100Z

members are fields I think here

alexmiller 2021-01-07T15:28:08.011500Z

oh, I guess it's methods and fields

orestis 2021-01-07T15:30:16.012100Z

Yeah… well actually going to the ancestor (the base class) yields these members:

(aadInstanceDiscoveryResponse
 aadInstanceDiscoveryResponse
 access$000
 access$100
 access$1000
 access$1100
 access$1200
 access$1300
 access$1400
 access$1500
 access$1600
 access$1700
 access$1800
 access$200
 access$300
 access$400
 access$500
 access$600
 access$700
 access$800
 access$900
 applicationName
 applicationName
 applicationVersion
 applicationVersion
 authenticationAuthority
 authority
 authority
 b2cAuthority
 build
 clientCapabilities
 clientCapabilities
 clientId
 com.microsoft.aad.msal4j.AbstractClientApplicationBase$Builder
 connectTimeoutForDefaultHttpClient
 connectTimeoutForDefaultHttpClient
 correlationId
 correlationId
 createDefaultAADAuthority
 executorService
 executorService
 httpClient
 httpClient
 logPii
 logPii
 onlySendFailureTelemetry
 onlySendFailureTelemetry
 proxy
 proxy
 readTimeoutForDefaultHttpClient
 readTimeoutForDefaultHttpClient
 self
 setTokenCacheAccessAspect
 sslSocketFactory
 sslSocketFactory
 telemetryConsumer
 telemetryConsumer
 tokenCacheAccessAspect
 validateAuthority
 validateAuthority)

orestis 2021-01-07T15:32:12.012800Z

OK, I think I’ve found it:

{:name authority,
  :type java.lang.String,
  :declaring-class
  com.microsoft.aad.msal4j.AbstractClientApplicationBase$Builder,
  :flags #{:private}}
 {:name authority,
  :return-type
  com.microsoft.aad.msal4j.AbstractClientApplicationBase$Builder,
  :declaring-class
  com.microsoft.aad.msal4j.AbstractClientApplicationBase$Builder,
  :parameter-types [java.lang.String],
  :exception-types [java.net.MalformedURLException],
  :flags #{:public}}

orestis 2021-01-07T15:32:44.013500Z

so there is a both a private field named authority and a public method, but they’re both on the parent abstract class

alexmiller 2021-01-07T15:33:03.013700Z

that should be fine

alexmiller 2021-01-07T15:33:16.014Z

. prefers method if both exist

alexmiller 2021-01-07T15:33:26.014200Z

(.- is always field)

orestis 2021-01-07T15:34:43.015100Z

Still doesn’t work though 😞

alexmiller 2021-01-07T15:34:46.015200Z

did you try type-hinting the arg to ^String? I doubt that would help since it's reporting it as String already, but I dunno

orestis 2021-01-07T15:34:55.015700Z

I’ve hinted yeah

orestis 2021-01-07T15:35:17.016500Z

I should be able to do (.-authority builder) right? but that throws the same exception

alexmiller 2021-01-07T15:35:26.016700Z

well it's private

orestis 2021-01-07T15:35:35.017Z

True

alexmiller 2021-01-07T15:35:37.017100Z

without really diving into guts of the reflection code, I can't really tell what's wrong

alexmiller 2021-01-07T15:35:57.017500Z

if you can file a repro at http://ask.clojure.org I will eventually look at it but can't atm

orestis 2021-01-07T15:37:22.018500Z

Is there any workaround you could think of? I could perhaps use reflection to make the field private and set it manually?

orestis 2021-01-07T15:37:50.019Z

I’ll file a repro. Does a git repo work for you or perhaps a deps.edn with a single .clj file?

alexmiller 2021-01-07T15:38:01.019200Z

or this is a variant of https://clojure.atlassian.net/browse/CLJ-1243

alexmiller 2021-01-07T15:38:30.019500Z

seems different than that though

alexmiller 2021-01-07T15:39:05.020500Z

ideally repro would be a clj -Sdeps ... and some code I can run with that

orestis 2021-01-07T15:39:05.020600Z

Hm, the javadoc shows T as the return argument for those. So perhaps they are generic.

orestis 2021-01-07T15:42:54.021100Z

I need to run, thanks @alexmiller for helping me figuring out some parts.

orestis 2021-01-07T15:43:07.021400Z

I’ll file a repro tomorrow. Have a great day!