ADAL Token Not Refreshing - asp.net

I have a ASP.NET webforms application in which I'm using Azure Key Vault in association with Azure Active directory. I've used the guide found here https://azure.microsoft.com/en-us/documentation/articles/storage-encrypt-decrypt-blobs-key-vault/
for getting a token from Azure Active Directory for my application and using it to access my key vault, which I'm ultimately using for storage encryption. Everything works well the first time the application requests a token, but after the token expires (an hour later). The application will not retrieve a new token as it should. I'm using the latest stable release Microsoft.IdentityModel.Clients.ActiveDirectory 2.19.208020213, and did try the latest pre-release (3.5.208051316-alpha) as well.
The GetToken method looks like this
Public Async Function GetToken(authority As String, resource As String, scope As String) As Task(Of String)
Dim authContext = New AuthenticationContext(authority)
Dim clientCred As New ClientCredential(CloudConfigurationManager.GetSetting("ClientID"), CloudConfigurationManager.GetSetting("ClientSecret"))
System.Diagnostics.Trace.TraceInformation("Attempting to acquire auth token")
Dim result As AuthenticationResult = await authContext.AcquireTokenAsync(resource, clientCred)
System.Diagnostics.Trace.TraceInformation("Auth returned")
If result Is Nothing Then
System.Diagnostics.Trace.TraceInformation("Auth was null")
Throw New InvalidOperationException("Failed to obtain the JWT token")
End If
System.Diagnostics.Trace.TraceInformation("Returning auth access token")
Return result.AccessToken
End Function
Which is used here to get a connection to the key vault
Dim cloudResolver As New KeyVaultKeyResolver(AddressOf GetToken)
The GetToken method just hangs at AcquireTokenAsync. I've turned on verbose logging in ADAL and this is what the log shows and it stops and GetToken never returns.
-Application: 2015-09-21T17:12:13 PID[8884] Information 9/21/2015 5:12:13 PM: 19ce5dc3-d618-48e9-8bbd-c5b3ad31bfc2 - TokenCache: Looking up cache for a token...
-Application: 2015-09-21T17:12:13 PID[8884] Information 9/21/2015 5:12:13 PM: 19ce5dc3-d618-48e9-8bbd-c5b3ad31bfc2 - TokenCache: An item matching the requested resource was found in the cache
-Application: 2015-09-21T17:12:13 PID[8884] Information 9/21/2015 5:12:13 PM: 19ce5dc3-d618-48e9-8bbd-c5b3ad31bfc2 - TokenCache: An expired or near expiry token was found in the cache
-Application: 2015-09-21T17:12:13 PID[8884] Information 9/21/2015 5:12:13 PM: 19ce5dc3-d618-48e9-8bbd-c5b3ad31bfc2 - TokenCache: An old item was removed from the cache
Further, I tried turning off token caching by setting the token cache to Nothing and then ADAL wouldn't even retrieve the access token the first time.

I found the answer in this similar question Azure KeyVault Active Directory AcquireTokenAsync timeout when called asynchronously
The key was to remove any of these and replace the them with await
.GetAwaiter().GetResult()
For example this was the original
Dim theKey = cloudResolver.ResolveKeyAsync($"{CloudConfigurationManager.GetSetting("KeyVaultUrl")}Secret/", CancellationToken.None).GetAwaiter().GetResult()
Which has been replaced with
Dim theKey = await cloudResolver.ResolveKeyAsync($"{CloudConfigurationManager.GetSetting("KeyVaultUrl")}Secret/", CancellationToken.None)

Related

Handle the revoked or expired Evernote app

One year ago I activated the Evernote API key for an app (for my client). One week ago the key expired. My client mistakenly revoked the app instead of authorizing it for one year more.
I restored the app authorization with the oAuth method:
var oAuth = new EvernoteOAuthNet.EvernoteOAuth(EvernoteOAuthNet.EvernoteOAuth.HostService.Production, "palmaross", "42dd922cb547c0b7", true);
var errorResponse = oAuth.Authorize();
if (!String.IsNullOrEmpty(errorResponse))
{
ENSessionAdvanced.SetSharedSessionDeveloperToken(oAuth.Token, oAuth.NoteStoreUrl);
}
Client successfully authorized the app for one year more:
Now the ENSessionAdvanced.SharedSession.IsAuthenticated = true. OK.
ENNoteStoreClient SC = ENSessionAdvanced.SharedSession.PrimaryNoteStore is OK.
But the SC.GetSyncState() now raises an exception of type EDAMUserException with AUTH_EXPIRED parameter. (Despite the fact the app was successfully authorized for one year more - see above).
For this reason few days ago i requested a new API key for this app,
With this key I have successfully connected my app with Evernote for one year.
But...
With the new API key (= new app?) the SC.GetSyncState() also raises the same exception - AUTH_EXPIRED!!
What can I do to solve the problem?

MSAL TokenAcquisition GetAccessTokenOnBehalfOfUser always fails because getaccounts is always empty

I have been trying to use Azure AD MSAL and ADAL and have NEVER been able to retrieve a token. I have tried the ALL of the samples and keep getting to the same issue, token is created, added to the EF cache DB but when the tokenAcquisition object tries to retrieve it, no account is found and fails to get token.
I have read through most (if not ALL) of the issues on GitHub and SO. this seems to be working for others but looks like numerous people have the same issue and I have yet to see an answer other then pointing me to the samples I have tried.
Simple question for the moment - how do I get accounts from the IConfidentialClientApplication?
I have NEVER been able to get a single account or a list of accounts.
Create app object:
var app = ConfidentialClientApplicationBuilder.CreateWithApplicationOptions(_applicationOptions)
.WithRedirectUri(currentUri)
.WithAuthority(authority)
.Build();
In GetAccessTokenOnBehalfOfUser:
IAccount account = await application.GetAccountAsync(accountIdentifier);
returns NULL
and
var accounts = await application.GetAccountsAsync();
returns an empty lists/IEnumerable.
I would expect to retrieve an account from
application.GetAccountAsync(accountIdentifier)
and a list from
await application.GetAccountsAsync();
OK, Finally found my issue.
The issue comes in using ASPNet identity logging into AzureAD as an external authority but using the identity to signin and create the claims principle.
I was mssing the AzureAD ObjectIdentifier from my claims. so the solution seems to be adding the ObjectIdentifier to the identity. I did this by using a ClaimsTransofrmation and looking for the auth type. If it was NOT Identity.Application it is from AzureAD and check to see if the User has the UserClaim and add it if not. This claim is then picked up and put in the principle's claims and under the covers, now the account is found....
if (principal.HasClaim(c => c.Type == SecurityConstants.ClaimTypes.ObjectId))
{
string oId = principal.FindFirstValue(SecurityConstants.ScpcClaimTypes.ObjectId);
var user = _usrMgr.FindByNameAsync(usrNm).Result;
List<Claim> claims = new List<Claim>(_usrMgr.GetClaimsAsync(user).Result);
if (!claims.Exists(c => c.Type == SecurityConstants.ScpcClaimTypes.ObjectId))
{
_usrMgr.AddClaimAsync(user, new Claim(SecurityConstants.ScpcClaimTypes.ObjectId, oId));
}

Evernote SetSharedSessionConsumerKey Does not Work in Outlook VBA Macro

I have a VBA macro in Outlook that moves a selected message into my archive folder and gets a url for the message. I also would like to add the message to Evernote like the "Save to Evernote" add-in and automatically add the url to the message as the url of the note.
I downloaded the COM setup for the Evernote Cloud SDK:
https://github.com/evernote/evernote-cloud-sdk-windows/tree/master/COM%20Setup
I then registered for and received my Evernote API Key for this application (Consumer Key and Consumer Secret).
I have an account in the sandbox.
I added a reference to the Evernote Cloud SDK and wrote some simple code to test that it is working.
However, the following code fails when checking the SharedSession.IsAuthenticated.
The code:
Public Sub CreateNote()
Const Key = "MY KEY"
Const Secret = "MY SECRET"
Const Host = "sandbox.evernote.com"
Dim evernoteSession As New ENSessionForCOM
Call evernoteSession.SetSharedSessionConsumerKey(Key, Secret, Host)
If evernoteSession.SharedSession.IsAuthenticated = False Then
evernoteSession.SharedSession.AuthenticateToEvernote
End If
End Sub
The error:
Run-time error '-2147024809 (80070057)'
Cannot create shared Evernote session without either a valid
consumer key/secret pair, or a developer token set.
I thought maybe I was trying too soon, but it has been almost 24 hours. What am I doing wrong?
After a lot of trial and error, I finally found a solution. Instead of an ENSessionForCOM, I needed to create an ENSessionAdvancedForCOM object. So now the code looks like this:
Public Sub CreateNote()
Const Key = "MY KEY"
Const Secret = "MY SECRET"
Const Host = "sandbox.evernote.com"
Dim evernoteSession As New ENSessionAdvancedForCOM
Call evernoteSession.SetSharedSessionConsumerKey(Key, Secret, Host)
If evernoteSession.SharedSession.IsAuthenticated = False Then
evernoteSession.SharedSession.AuthenticateToEvernote
End If
End Sub
And it now authenticated.

"Access Denied" error on Google Auth API for Calendar

I have been trying since yesterdar to authenticate my requests to de Google Calendar V3 API in order to use it, but I am unable to pass through an AggregateException which contains just the text "Access Denied".
My conflictive code is this, being the last line the one who breaks:
UserCredential credential;
using (var stream =
new FileStream(HostingEnvironment.MapPath(credentialsPath), FileMode.Open, FileAccess.Read))
{
string credPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, writePath);
var authTask = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)
);
credential = authTask.Result;
}
I have already tried recreating the secret key, generating the client_secret.json file again, creating another credentials... also I know that both paths, the JSON and the folder are correct, because I had to solve that before reaching this error.
Any hints on what can be the problem?
Thanks!
"Access Denied" error is usually encountered due to Invalid Credentials.
Here are the suggested actions that you can try:
Get a new access token using the long-lived refresh token.
If this fails, direct the user through the OAuth flow, as described in Authorizing requests with OAuth 2.0.
If you are seeing this for a service account, check that you have successfully completed all the steps in the service account page.
Hope that helps!

Get token from ADFS

I'm trying to obtain a token from ADFS to that I can use it with an on-premise Windows Service Bus installation. I may not have ADFS properly configured because I get the following message:
MSIS3127: The specified request failed.
The code to access the token is as follows:
string adrecaSTS = "trust/13/usernamemixed";
WS2007HttpBinding binding = new WS2007HttpBinding();
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential; //https
string baseSSLUri = #"https://<myadfs>/adfs/services/";
WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress(baseSSLUri + adrecaSTS));
trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
trustChannelFactory.Credentials.UserName.UserName = "username";
trustChannelFactory.Credentials.UserName.Password = "password";
WSTrustChannel tokenClient = (WSTrustChannel)trustChannelFactory.CreateChannel();
//create a token issuance issuance
RequestSecurityToken rst = new RequestSecurityToken(RequestTypes.Issue);
//call ADFS STS
SecurityToken token = tokenClient.Issue(rst);
The endpoint is enabled on ADFS and my client (laptop on separate domain) trusts the certificate from ADFS.
Do I need to set up some kind of trust or something further? This error message is not particularly helpful.
See here:
https://github.com/thinktecture/Thinktecture.IdentityServer.v2/blob/master/src/Libraries/Thinktecture.IdentityServer.Protocols/WSFederation/HrdController.cs
The ValidateToken method has most of the code - but you first need to extract the InnerXml from the generic token and turn that into a SAML security token (again using a token handler).
Found the issue. I was trying to log on as an administrator account. When I used a regular user it worked.
I also had to modify the RequestSecurityToken to have a KeyType of KeyType.Symmetric
I see that you solved your issue, but here is some additional inforamation to potentially help others that might have the same error message but a different cause.
The AD FS error, "MSIS3127...", can have multiple causes. For us, it was caused by one of our relying party claim rules specifying an AD FS attribute store that didn't exist.
In order to debug the error, we checked the Event Viewer on all of the servers running AD FS, and that's where we found the detailed message that called out the attribute store problem. So, if anyone else gets the same error message, then I suggest checking the Event Viewer on AD FS to see if there are additional logs.
Note that AD FS logs to the Event Viewer under the folder/node of Applications and Services Logs => AD FS => Admin

Resources