darkmoonka commented on PR #184:
URL: 
https://github.com/apache/santuario-xml-security-java/pull/184#issuecomment-1607276879

   > Hmmm. What if I have one thread which preconfigures the `providerName` for 
some thread pool? Now they would get `null`. On the other hand you are right 
that the class is not thread-safe at all, it is just a global unprotected 
variable.
   > 
   > Javadoc says it is just a default and when I take a look on how it is used:
   > 
   > ```
   >            if (provider == null) {
   >                 String providerId = JCEMapper.getProviderId();
   >                 if (providerId == null) {
   >                     this.signatureAlgorithm = 
Signature.getInstance(algorithmID);
   > 
   >                 } else {
   >                     this.signatureAlgorithm = 
Signature.getInstance(algorithmID, providerId);
   >                 }
   > 
   >             } else {
   >                 this.signatureAlgorithm = 
Signature.getInstance(algorithmID, provider);
   >             }
   > ```
   > 
   > and the same for MessageDigest instead of Signature.
   > 
   > Then I believe that much safer is to use rather 
`Signature.getInstance(algorithmID, provider);` and 
`MessageDigest.getInstance(algorithmID, provider);` with the `provider` you set 
to the `providerName` now, and completely avoid relying on the default 
non-final value.
   > 
   > Btw it is also bit weird that the same value is used as a default for 
`MessageDigest` and `Signature`, mhm ... seems it is really a "global default 
provider".
   
   Hello @dmatej,
   
   thanks for your hints!
   However, something feels wrong with the `null` case.
   I would use the default `null` provider for signature validation and another 
non-null provider for signing.
   ```
               if (provider == null) {
                   String providerId = JCEMapper.getProviderId();
                   if (providerId == null) {
                       this.signatureAlgorithm = 
Signature.getInstance(algorithmID);
   
                   } else {
                       this.signatureAlgorithm = 
Signature.getInstance(algorithmID, providerId);
                   }
   
               } else {
                   this.signatureAlgorithm = Signature.getInstance(algorithmID, 
provider);
               }
   ```
   This code falls back to the default provider - fetched from the `JCEMapper` 
- in case the provider is `null`.
   Is there a way to somehow differentiate between the "default" and a "null"?
   
   In my code, I use xmlsec together with OpenSAML4 and it does not pass any 
providers to the constructors of the `Signature` objects.
   If I have an IDP that can verify the signature of an AuthnRequest from and 
SP and sign a SAML Response or Assertion in parallel, then the concurrency 
issue appears.
   I would solve the root cause, that I think is that the default provider 
configuration in `JCEMapper` is global, but 3rd party libraries do not handle 
it as a last resort fallback value.
   
   Can it cause any problem if we change the `providerName` to `ThreadLocal`? 
Meaning the global would always be thread specific.
   If it is a problem, I would have another idea: what if we introduce a 
thread-safe provider configuration next to the global default, and the 
`getProviderId` method would return the value of the `ThreadLocal` variable if 
it is not null, otherwise the global one. This change would be backward 
compatible as long the default value of the `ThreadLocal` provider is `null`.
   I checked wss4j and OpenSAML that depend on xmlsec, and neither of them call 
the `setProviderId` method, so the following would be safe:
   
   ```
   ...
       private static String globalProviderName;
   
       private static ThreadLocal<String> threadSpecificProviderName = new 
ThreadLocal<>();
   
   ...
       /**
        * Gets the default Provider for obtaining the security algorithms
        * @return the default providerId.
        */
       public static String getProviderId() {
           if (threadSpecificProviderName.get() != null) {
               return threadSpecificProviderName.get();
           }
           return globalProviderName;
       }
   
       /**
        * Sets the default Provider for obtaining the security algorithms
        * @param provider the default providerId.
        * @throws SecurityException if a security manager is installed and the
        *    caller does not have permission to register the JCE algorithm
        */
       public static void setProviderId(String provider) {
           JavaUtils.checkRegisterPermission();
           globalProviderName = provider;
       }
   
       public static void setThreadSpecificProviderName(String 
threadSpecificProviderName) {
           JavaUtils.checkRegisterPermission();
           JCEMapper.threadSpecificProviderName.set(threadSpecificProviderName);
       }
   ...
   ```
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to