MSAL4J with Extensions error: com.microsoft.aad.msal4jextensions.CrossProcessCacheFileLock - null - msal

I try to authenticate to Azure AD throught MSAL4J Java library (https://github.com/AzureAD/microsoft-authentication-library-for-java) with extention (https://github.com/AzureAD/microsoft-authentication-extensions-for-java) for cross platform cache serialization.
I am using the "Desktop app that calls web APIs: Acquire a token interactively" flow (https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-acquire-token-interactive?tabs=dotnet)
Here is my code:
private static IAuthenticationResult acquireTokenInteractive(final boolean onlyFromCache) throws Exception {
scopeSet.add(API_SCOPE);
final PersistenceTokenCacheAccessAspect perSettings = new PersistenceTokenCacheAccessAspect(createPersistenceSettings());
pca = PublicClientApplication.builder(CLIENT_ID).authority(AUTHORITY).setTokenCacheAccessAspect(perSettings).build();
final Set<IAccount> accountsInCache = pca.getAccounts().join();
IAuthenticationResult result;
try {
// Take first account in the cache. In a production application, you would filter
// accountsInCache to get the right account for the user authenticating.
final IAccount account = accountsInCache.iterator().next();
final SilentParameters silentParameters = SilentParameters.builder(scopeSet, account).build();
// try to acquire token silently. This call will fail since the token cache
// does not have any data for the user you are trying to acquire a token for
result = pca.acquireTokenSilently(silentParameters).join();
} catch (final Exception ex) {
if ((ex.getCause() instanceof MsalException) || (ex instanceof NoSuchElementException)) {
if (!onlyFromCache) {
final InteractiveRequestParameters parameters = InteractiveRequestParameters.builder(new URI("http://localhost"))
.scopes(scopeSet).build();
// Try to acquire a token interactively with system browser. If successful, you should see
// the token and account information printed out to console
result = pca.acquireToken(parameters).join();
} else {
return null;
}
} else {
// Handle other exceptions accordingly
throw ex;
}
}
return result;
}
I get an error while accessing cache:
[ForkJoinPool.commonPool-worker-19] ERROR com.microsoft.aad.msal4jextensions.CrossProcessCacheFileLock - null
and when I try to acquire token, an exception is thrown after a valid login in the browser (Firefox) :
java.util.concurrent.CompletionException:
java.lang.AbstractMethodError: Receiver class
com.sun.jna.platform.win32.WinCrypt$DATA_BLOB does not define or
inherit an implementation of the resolved method 'abstract
java.util.List getFieldOrder()' of abstract class
com.sun.jna.Structure. at
java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
at
java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
at
java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
at
java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
at
java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at
java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at
java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at
java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.AbstractMethodError: Receiver class
com.sun.jna.platform.win32.WinCrypt$DATA_BLOB does not define or
inherit an implementation of the resolved method 'abstract
java.util.List getFieldOrder()' of abstract class
com.sun.jna.Structure. at
com.sun.jna.Structure.fieldOrder(Structure.java:952) at
com.sun.jna.Structure.getFields(Structure.java:1006) at
com.sun.jna.Structure.deriveLayout(Structure.java:1172) at
com.sun.jna.Structure.calculateSize(Structure.java:1097) at
com.sun.jna.Structure.calculateSize(Structure.java:1049) at
com.sun.jna.Structure.allocateMemory(Structure.java:403) at
com.sun.jna.Structure.(Structure.java:194) at
com.sun.jna.Structure.(Structure.java:182) at
com.sun.jna.Structure.(Structure.java:169) at
com.sun.jna.Structure.(Structure.java:161) at
com.sun.jna.platform.win32.WinCrypt$DATA_BLOB.(WinCrypt.java:74)
at
com.sun.jna.platform.win32.Crypt32Util.cryptProtectData(Crypt32Util.java:80)
at
com.sun.jna.platform.win32.Crypt32Util.cryptProtectData(Crypt32Util.java:60)
at
com.sun.jna.platform.win32.Crypt32Util.cryptProtectData(Crypt32Util.java:47)
at
com.microsoft.aad.msal4jextensions.persistence.CacheFileAccessor.write(CacheFileAccessor.java:56)
at
com.microsoft.aad.msal4jextensions.PersistenceTokenCacheAccessAspect.afterCacheAccess(PersistenceTokenCacheAccessAspect.java:144)
at
com.microsoft.aad.msal4j.TokenCache$CacheAspect.close(TokenCache.java:171)
at com.microsoft.aad.msal4j.TokenCache.saveTokens(TokenCache.java:218)
at
com.microsoft.aad.msal4j.AbstractClientApplicationBase.acquireTokenCommon(AbstractClientApplicationBase.java:131)
at
com.microsoft.aad.msal4j.AcquireTokenByAuthorizationGrantSupplier.execute(AcquireTokenByAuthorizationGrantSupplier.java:63)
at
com.microsoft.aad.msal4j.AcquireTokenByInteractiveFlowSupplier.acquireTokenWithAuthorizationCode(AcquireTokenByInteractiveFlowSupplier.java:193)
at
com.microsoft.aad.msal4j.AcquireTokenByInteractiveFlowSupplier.execute(AcquireTokenByInteractiveFlowSupplier.java:39)
at
com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:71)
at
com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:20)
at
java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
... 6 more
What am I doing wrong ?
Thanks by advance !

Related

How to properly handle Exceptions in client thrown by a SOAP web service

I am setting up a Client using Spring-boot in Java to access a soap endpoint (for testing purpose).What's the best approach to handle Exceptions? I want to handle SOAPFaultClientExceptions...
I have already tried this:
How to Parse SoapFaultClientException in spring-ws
but it didn't work properly, as I couldn't call the getValue() method on detail
try {
JAXBElement res = (JAXBElement) getWebServiceTemplate().marshalSendAndReceive(url, request);
return (GetBankResponseType) res.getValue();
}catch (SoapFaultClientException ex) {
SoapFaultDetail soapFaultDetail = ex.getSoapFault().getFaultDetail(); // <soapFaultDetail> node
// if there is no fault soapFaultDetail ...
if (soapFaultDetail == null) {
throw ex;
}
SoapFaultDetailElement detailElementChild = soapFaultDetail.getDetailEntries().next();
Source detailSource = detailElementChild.getSource();
Object detail = getWebServiceTemplate().getUnmarshaller().unmarshal(detailSource);
JAXBElement source = (JAXBElement) detail;
System.out.println("Text::"+source.getValue());
}//catch other Exceptions...Which ones?
return null;
}
Expected result is a handled Exception, (SOAPFaultClientException) or others... which get Thrown by the webservice when wrong parameters are passed. I don't find any suitable solutions.
Configure ClientInterceptor or FaultMessageResolver to your WebServiceTemplate and do your error handling there.

Java Lang Illegal State Exception for GoogleClientManager Logout in Xamarin Forms

I'm using https://www.pujolsluis.com/google-client-plugin-for-xamarin/ for google sign in xamarin forms. Both Login and Logout methods work fine; but i have to hide the login page after successful login.After opening the app from second time onwards, logout method throws java.Lang.IlegalStateException<Timeout exceeded getting exception details> ,cannot logout.Active token is null.How to handle this exception? How to logout successfully from second time?
Login:
public IGoogleClientManager googleClientManager;
googleClientManager = CrossGoogleClient.Current;
private void google_btn_Clicked(object sender, EventArgs e)
{
if (CrossConnectivity.Current.IsConnected)
{
googleClientManager.LoginAsync();
googleClientManager.OnLogin += OnLoginCompleted;
// CrossGoogleClient.Current.SilentLoginAsync();
// var userToken = CrossGoogleClient.Current.ActiveToken;
}
else
{
DependencyService.Get<IToast>().LongAlert("Check Connection!");
}
}
public async void OnLoginCompleted(object s,
GoogleClientResultEventArgs<GoogleUser> loginEventArgs)
{
if (loginEventArgs.Data != null)
{
GoogleUser googleUser = loginEventArgs.Data;
string google_name = googleUser.Name;
string google_mail = googleUser.Email;
Uri google_img = googleUser.Picture;
googleClientManager.OnLogin -= OnLoginCompleted;
}
}
Logout:
public void Logout()
{
googleClientManager.OnLogout += OnLogoutCompleted;
googleClientManager.Logout(); // throws exception from secondtime after hiding loginpage
}
private void OnLogoutCompleted(object sender, EventArgs loginEventArgs)
{
googleClientManager.OnLogout -= OnLogoutCompleted;
}
You are getting this exception because you are trying to log out of a google client that is no longer connected as the message of the exception states.
Google Client Illegal State Exception Screenshot
To solve this you could do two things, fix the logic in your app to persist the logout state, so you don't try and log out when the user is not actually logged in anymore. Or you could enable the ActiveToken and add an if statement before trying to log out to verify if it's null or not you can do so by following the steps on the getting started guide on the project repo: https://github.com/CrossGeeks/GoogleClientPlugin/blob/master/GoogleClient/docs/GettingStarted.md
Activate ActiveToken Google Client Plugin Guide Screenshot

Error/Exception while marshalling signed and encrypted response OpenSAML v3

I have been using OpenSaml V2 for a while, which has been working well, and I recently started the migration. Due to the lack of information, even from the OpenSaml V3 book I have recently purchase, I am having some issues with a few things that were working fine with V2.
I have been using the following method to encrypt the Assertion. This method seems to be working fine.
private EncryptedAssertion createEncryptedAssertion(Assertion assertion) throws SamlException {
try {
Credential keyEncryptionCredential = CredentialSupport.getSimpleCredential(this.encryptingCertificate, this.encryptingPrivateKey);
DataEncryptionParameters encryptionParameters = new DataEncryptionParameters();
encryptionParameters.setAlgorithm(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128);
KeyEncryptionParameters keyEncryptionParameters = new KeyEncryptionParameters();
keyEncryptionParameters.setEncryptionCredential(keyEncryptionCredential);
keyEncryptionParameters.setAlgorithm(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP);
Encrypter samlEncrypter = new Encrypter(encryptionParameters, keyEncryptionParameters);
samlEncrypter.setKeyPlacement(Encrypter.KeyPlacement.INLINE);
return samlEncrypter.encrypt(assertion);
}
catch(Exception e) {
throw new SamlException(e);
}
}
The problem I am having happens when I try to marshall my response with the encrypted assertion, using the following method:
public String marshall(XMLObject xmlObject, boolean encode) throws SamlException {
try {
ParserPool parserPool = XMLObjectProviderRegistrySupport.getParserPool();
MarshallerFactory marshallerFactory = XMLObjectProviderRegistrySupport.getMarshallerFactory();
Marshaller marshaller = marshallerFactory.getMarshaller(xmlObject);
if(marshaller == null) {
throw new SamlException("Unable to locate marshaller for " + xmlObject.getElementQName()
+ " can not perform marshalling operation");
}
Element element = marshallerFactory.getMarshaller(xmlObject).marshall(xmlObject, parserPool.newDocument());
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(element);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
if(encode) {
//return Util.base64EncodeMessage(xmlString);
}
return xmlString;
}
catch(Exception e) {
throw new SamlException(e);
}
}
When I try to marshall my response with encrypted assertion, I get the following exception:
Caused by: org.opensaml.core.xml.io.MarshallingException: Unable to root namespaces of cached DOM element, {http://www.w3.org/2001/04/xmlenc#}EncryptionMethod
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.prepareForAdoption(AbstractXMLObjectMarshaller.java:427)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:144)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallChildElements(AbstractXMLObjectMarshaller.java:271)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallInto(AbstractXMLObjectMarshaller.java:212)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:162)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallChildElements(AbstractXMLObjectMarshaller.java:271)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallInto(AbstractXMLObjectMarshaller.java:212)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:162)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallChildElements(AbstractXMLObjectMarshaller.java:271)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallInto(AbstractXMLObjectMarshaller.java:212)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:162)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallChildElements(AbstractXMLObjectMarshaller.java:271)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallInto(AbstractXMLObjectMarshaller.java:212)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:162)
at org.opensaml.saml.common.AbstractSAMLObjectMarshaller.marshall(AbstractSAMLObjectMarshaller.java:65)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallChildElements(AbstractXMLObjectMarshaller.java:271)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallInto(AbstractXMLObjectMarshaller.java:212)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:118)
at org.opensaml.saml.common.AbstractSAMLObjectMarshaller.marshall(AbstractSAMLObjectMarshaller.java:57)
at com.divinvest.sso.opensaml.SamlAssertionProducerV2.marshall(SamlAssertionProducerV2.java:171)
... 25 more
Caused by: org.w3c.dom.DOMException: Unable to resolve namespace prefix ds found on element {http://www.w3.org/2000/09/xmldsig#}DigestMethod
at net.shibboleth.utilities.java.support.xml.NamespaceSupport.rootNamespaces(NamespaceSupport.java:247)
at net.shibboleth.utilities.java.support.xml.NamespaceSupport.rootNamespaces(NamespaceSupport.java:295)
at net.shibboleth.utilities.java.support.xml.NamespaceSupport.rootNamespaces(NamespaceSupport.java:200)
at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.prepareForAdoption(AbstractXMLObjectMarshaller.java:422)
... 44 more
Am I missing anything in the unmarshall method? I am marshall my response objects with signed assertion, signed response but when the assertion is encrypted, I am not able to.
Thank you
The issue was that xmltooling was bringing the wrong xmlsec version (1.5.7), I had to include an exclusing in order to use xmlsec 2.0.5 that is using by opensaml-security-api.

Display message to user on expired session when using wicket-auth-roles

Hi I have been unable to solve the following problem in Wicket 6.*:
In our webapp we are using wicket-auth-roles to manage authentication/authorization. When session expires, user should be redirected to a page set by getApplicationSettings().setPageExpiredErrorPage(SomePage.class) on his next action. However, if the user tries to access a page which doesn't allow guests, he is redirected to a login page skipping the PageExpiredPage altogether.
My question is - how can I display "Session has expired." message to the user?
Among other things, I have tried session.info("message") during onInvalidate phase of session's lifecycle, however the feedback message is then rendered on the first page after login (not on the login page).
Thank you for your anwsers.
You could use a RequestCycleListener to record when a PageExpiredException is thrown.
public class ExceptionMapperListener extends AbstractRequestCycleListener {
#Override
public IRequestHandler onException(RequestCycle cycle, Exception ex) {
if (ex instanceof PageExpiredException) {
// Record in session or request cycle
// OR
// Create a RenderPageRequestHandler yourself and add a page parameter
// See DefaultExceptionMapper#internalMap(Exception)
}
return null;
}
}
// In Application#init():
getRequestCycleListeners().add(new ExceptionMapperListener());
ORINAL ANSWER
(kept because it could still help...)
I haven't tried it myself since I don't use wicket-auth-roles, but try overriding the method AuthenticatedWebApplication#restartResponseAtSignInPage() with something like this:
if (isSessionExpired()) {
PageParameters params = new PageParameters();
params.add("showSessionExpired", true);
throw new RestartResponseAtInterceptPageException(getSignInPageClass(), params);
} else {
throw new RestartResponseAtInterceptPageException(getSignInPageClass());
}
And then in the SignInPageClass, display the desired message if the showSessionExpired page parameter is present.
I'm not sure how you implement isSessionExpired(), but you seem to have that part already covered.
OR
Depending on how you implemented isSessionExpired(), maybe you could do the following in your SignInPageClass:
if (sessionExpired()) {
session.info("message")
}
After bernie put me on the right path, I eventually figured out a solution to the problem:
First it is required to override RequestCycleListener:
public class SessionExpiredListener extends AbstractRequestCycleListener {
public void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler) {
if (handler instanceof IPageRequestHandler) {
IPageRequestHandler pageHandler = (IPageRequestHandler) handler;
HttpServletRequest request = (HttpServletRequest) cycle.getRequest().getContainerRequest();
//check whether the requested session has expired
boolean expired = request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid();
//check whether the requested page can be instantiated with the current session
boolean authorized = Session.get().getAuthorizationStrategy().isInstantiationAuthorized(pageHandler.getPageClass());
if (expired && !authorized) {
throw new PageExpiredException("Session has expired!");
}
}
super.onRequestHandlerResolved(cycle, handler);
}
}
Check for authorized prevents the session-expired message from displaying on log-out or when accessing unprotected pages.
Finally, you must register your listener and PageRequestHandlerTracker in your WebApplication:
getRequestCycleListeners().add(new SessionExpiredListener());
getRequestCycleListeners().add(new PageRequestHandlerTracker());

"A registration already exists for URI" when using HttpSelfHostServer

We are having an issue unit test failing because previous tests haven't closed session of HttpSelfHostServer.
So the second time we try to open a connection to a sever we get this message:
System.InvalidOperationException : A registration already exists for URI 'http://localhost:1337/'.
This test forces the issue (as an example):
[TestFixture]
public class DuplicatHostIssue
{
public HttpSelfHostServer _server;
[Test]
public void please_work()
{
var config = new HttpSelfHostConfiguration("http://localhost:1337/");
_server = new HttpSelfHostServer(config);
_server.OpenAsync().Wait();
config = new HttpSelfHostConfiguration("http://localhost:1337/");
_server = new HttpSelfHostServer(config);
_server.OpenAsync().Wait();
}
}
So newing up a new instance of the server dosent seem to kill the previous session. Any idea how to force the desposal of the previous session?
Full exception if it helps?
System.AggregateException : One or more errors occurred. ----> System.InvalidOperationException : A registration already exists for URI 'http://localhost:1337/'.
at
System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait()
at ANW.API.Tests.Acceptance.DuplicatHostIssue.please_work() in DuplicatHostIssue.cs: line 32
--InvalidOperationException
at System.Runtime.AsyncResult.End(IAsyncResult result)
at System.ServiceModel.Channels.CommunicationObject.EndOpen(IAsyncResult result)
at System.Web.Http.SelfHost.HttpSelfHostServer.OpenListenerComplete(IAsyncResult result)
You might want to write a Dispose method like below and call it appropriately to avoid this issue
private static void HttpSelfHostServerDispose()
{
if (server != null)
{
_server.CloseAsync().Wait();
_server.Dispose();
_server = null;
}
}
This will clear the URI register.

Resources