AADSTS70002: Error validating credentials. AADSTS50013: Assertion is not within its valid time range. error in memory dump using WinDbg - windbg

Recently we had a production deployment of normal windows store app. It was working fine for few days and after some days performance is very very slow. Our application follows Gate keeper pattern where store app hits gate keeper and gate keeper to rest service and rest service to database (everything is hosted in cloud).
After analyzing we found that Gatekeeper web app is taking more time to respond. We have taken memory dump for the web app and analyzed using WinDbg and found an issue with AAD access token where lock count is measured as 2. And attached is the result taken from memory dump.
Here is the actual code to get access token (we are using cert based authentication)
public static void GetCert()
{
try
{
var clientAssertionCertPfx = Helper.FindCertificateByThumbprint(WebConfigurationManager.AppSettings["CertificateThumbPrint"]);
AssertionCert = new ClientAssertionCertificate(WebConfigurationManager.AppSettings["ida:ClientID"], clientAssertionCertPfx);
}
catch (Exception ex)
{
throw ex;
}
}
public static async Task<string> GetAccessToken(string authority, string resource, string scope)
{
try
{
string userName = "";
GetCert();
var context = new AuthenticationContext(authority, TokenCache.DefaultShared);
AuthenticationResult result = null;
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
if (bootstrapContext != null)
{
userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
if (!string.IsNullOrEmpty(bootstrapContext.Token))
{
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationContext authContext = new AuthenticationContext(authority);
result = await authContext.AcquireTokenAsync(resource, AssertionCert, userAssertion);
return result != null ? result.AccessToken : null;
}
return null;
}
else
{
return null;
}
}
catch (Exception ex)
{
LogErrorDetails objLogDetails = new LogErrorDetails();
ErrorLog objErrorLog = new ErrorLog();
objLogDetails.ErrorDescription = ex.Message;
objLogDetails.ErrorNumber = ex.HResult;
objLogDetails.strErrorContext = "Helper";
objLogDetails.strErrorContextArea = "GetAccessToken";
objLogDetails.strTrace = ex.StackTrace;
await objErrorLog.InsertErrorLog(objLogDetails);
return null;
}
}
While running this code locally we are not getting any issue with the access token and it is fast. Only in production environment performance is very slow and not sure it is with the access token or any other parameter.
Could you please help us in analyzing what went wrong with our code.

Related

.netcore 3 client certificate with HttpClient

I have a .netcore 3 project (WorkerService Template) which sends JSON data to a REST endpoint. The requests are sent via a HttpClient and configured to use a client certificate which the server requires. The server response is always 200 and HTML characters. According to the server managers the request is redirected to the home page of the web server, because the client machine is being correctly handled with a specific user but no certificate is available. I am using the following code:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("client").ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
X509Certificate2 certificate = GetCertificate(Configuration.CertificateSubjectKeyIdentifier);
handler.ClientCertificates.Add(certificate);
return handler;
}
}
GetCertificate retrieves the certificate from the Certificate Store:
private X509Certificate2 GetCertificate(string subjectIdentifier)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var collection = store.Certificates;
var certificates = collection.Find(X509FindType.FindBySubjectKeyIdentifier, subjectIdentifier, true);
foreach (var certificate in certificates)
{
if (DateTime.Compare(DateTime.Parse(certificate.GetExpirationDateString()), DateTime.Now) >= 0)
{
Logger.LogInformation($"Loaded X.509 certificate {certificate.Subject} issued by {certificate.Issuer}, valid from {certificate.GetEffectiveDateString()} to {certificate.GetExpirationDateString()}");
return certificate;
}
}
Logger.LogError($"X.509 certificate not loaded: No valid certificate could be found.");
return null;
}
Code which sends a request:
public async Task<ResponseData> PostAsync<T>(string url, T dataToSend)
{
ResponseData result = null;
HttpResponseMessage httpResponseMessage = null;
try
{
var errorHttp = false;
HttpClient httpClient;
using (httpClient = HttpClientFactory.CreateClient("client)) // IHttpClientFactory initialized in ctor
{
HttpContent httpContent;
using (httpContent = CreateJsonHttpContent(dataToSend, MediaType.ApplicationJson)) //build JSON from data
{
httpResponseMessage = await httpClient.PostAsync(url, httpContent).ConfigureAwait(false);
result = BuildResponseData(httpResponseMessage); //writes response data in a class
if (httpResponseMessage?.IsSuccessStatusCode == true)
{
result.Content = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
else
{
errorHttp = true;
}
if (errorHttp)
{
var httpRequestException = new HttpRequestException($"The http request to {url} was not successful.");
Logger.LogError($"{httpRequestException.Message} : {httpRequestException.InnerException}");
Logger.LogError(httpRequestException.StackTrace);
}
}
}
}
catch (SocketException socketException)
{
Logger.LogError($"{socketException.Message} : {socketException.InnerException}");
result = new ResponseData(socketException);
}
catch (WebException wex)
{
Logger.LogError($"{wex.Message} : {wex.InnerException}");
if (wex.Status == WebExceptionStatus.ConnectFailure || wex.Status == WebExceptionStatus.Timeout)
{
Logger.LogError($"Cannot connect to the rest service : {WebExceptionStatus.Timeout}");
}
}
catch (Exception ex)
{
LogException(ref ex);
result = new ResponseData(ex);
}
finally
{
httpResponseMessage?.Dispose();
}
return result;
}
The class which uses the PostAsync method is also registered in the ServiceCollection. Any ideas what could be wrong here? Could it also be that the certificate is not being handled correctly on the server side?
My strong suspection is the misconfiguration on client (your) end. Your application reads for certificate from LocalMachine store. By default, only local administrator and SYSTEM account can read/use private keys for certificates installed in LocalMachine store.
Either, install the certificate in CurrentUser store of a user account under which the client application is running, or explicitly grant private key permissions to user account under which the client application is running. To do this:
Open Certificates MMC snap-in under LocalMachine context (certlm.msc)
Expand Personal\Certificates
Select desired certificate, right-click and then Manage Private Keys menu item.
Grant Read permissions to user account under which the client application is running.
In this case, you don't need to modify your code or move certificate between stores.

Filter data from azure database using Mobile Service client

I am trying to restrict the data returned by the Mobile App service hosted on Azure portal. Unfortunately I am unable to restrict the data before it's returned (at the createQuery() stage). The filter works only when applied after the data is returned. Here is a sample code. The app is written in Xamarin forms on iOS platform.
public async Task<IEnumerable<Company>> GetCompanies(string
cityId)
{
await App.MobileService.SyncContext.InitializeAsync(store,
handler);
this.companies = App.MobileService.GetSyncTable<Company>();
try
{
await App.MobileService.SyncContext.PushAsync();
// Filter is unsuccessful here
await this.companies.PullAsync("all_companies",
this.companies.CreateQuery().Where(x => x.City_Id ==
cityId)).ConfigureAwait(false);
}
catch (MobileServicePushFailedException ex)
{
string ErrorString = string.Format("Push failed because
of Company sync errors: {0} errors, message:
{1}",ex.PushResult.Errors.Count, ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine("Exception Sync companies: " + ex);
}
// Filter works here. But its too late as it has already
// pulled all the unnecessary data
return await companies.Where(x => x.City_Id ==
cityId).OrderBy(c => c.Id).ToEnumerableAsync();
}

Box Java SDK Retrieve acces/refresh tokens

I am trying to create a java program that will search for certain files in Box Storage. For this i am trying to use the Box Java SDK and i created an application in Box (https://app.box.com/developers/services).
When i use the developer token i am able to traverse through my box parent/child folders. Since this token is valid for 60 mins i want to programmatically retrieve and set the token. When i looked at the manuals it says to manully call api's to get these tokens.
I tried the below code..
BoxAPIConnection api = new BoxAPIConnection(clientid,clientsecret);
String accesstoken = api.getAccessToken();
String refreshtoken = api.getRefreshToken();
I dont want to throw a box login page to the user and want to run this program as a daemon which will search files and spit out some report text file.
Thanks for all the help.
It is possible to manage Box login through code.
For the first time you access Box.com and get the client id, client secret, access token and refresh token.
Save it in DB or property file.
Use below code, and each and every time update the actual access and refresh token.
String accessToken = // access token from DB/property
String refreshToken = // refresh token from DB/property
String boxClientId = // client id from DB/property
String boxClientSecret = // client secret from DB/property
try {
BoxAPIConnection api = new BoxAPIConnection(boxClientId, boxClientSecret, accessToken, refreshToken);
api.addListener(new BoxAPIConnectionListener() {
#Override
public void onRefresh(BoxAPIConnection api) {
String newAccessToken = api.getAccessToken();
String newrefreshToken = api.getRefreshToken();
// update new access and refresh token in DB/property
}
#Override
public void onError(BoxAPIConnection api, BoxAPIException error) {
LOGGER.error("Error in Box account details. " + error.getMessage());
}
});
LOGGER.debug("Completed Box authentication");
} catch (Exception e) {
LOGGER.error("Error in Box authentication. Error msg : " + e.getMessage());
}
If you use a state.conf file, you'll be able to refresh the token/refres_token pair programmatically without getting an auth code. Here's a code snippet that I use:
private static BoxAPIConnection getBoxAPIConnection(String client_id, String client_secret, String token, String refresh_token, String stateConfPath) {
String state = null;
try {
logger.info("Getting state.conf: " + stateConfPath + "/state.conf");
InputStream fis = new FileInputStream(stateConfPath + "/state.conf");
InputStreamReader isr = new InputStreamReader(fis, Charset.forName("UTF-8"));
BufferedReader br = new BufferedReader(isr);
state = br.readLine();
}
catch (FileNotFoundException f) {
try {
// create file if it doesn't exist
PrintWriter writer = new PrintWriter(stateConfPath + "/state.conf", "UTF-8");
writer.println("");
writer.close();
}
catch (Exception w) {
logger.fatal("Exception", w);
}
}
catch (IOException e) {
logger.fatal("IOException", e);
}
BoxAPIConnection api = null;
//if (null == state || "".equals(state)) {
if (!token.equals("") && !refresh_token.equals("")) {
api = new BoxAPIConnection(client_id, client_secret, token, refresh_token);
} else {
logger.info("Restoring state..." + state);
api = BoxAPIConnection.restore(client_id, client_secret, state);
if (api.needsRefresh()) { // this is not a reliable call. It can still throw a 401 below
logger.info("api refreshing...");
api.refresh();
}
else {
logger.info("api good...");
}
}
return api;
}

Google API consent screen not showing up on after publishing to server

I am working with the Google Provisioning API. I have used Web Application type project from Google developer console. I have used Diamto blog and samples and it works perfectly on my local with all options like FileStore, Custom File Store, Service Account etc but when I uploaded on server user consent screen just doesn't pops up with any options like FileStore, Custom File Store. I spent days to figure out problem and solutions but nothing has worked for me so far.
my configuration
My server configuration is windows server 2008 datacenter r2,.net 4.5,IIS 7.5.
Service account works perfectly but I need to do it by Consent screen so Web Application type of project.
I have used google .net client library with version 1.9.2.27817.
I am just highlighting main code where it gets stuck and rest is same as per Diamto post and github examples.
Let me know if you need more info.
Code
public static DirectoryService AuthenticateOauth(string clientId, string clientSecret, string userName, IDataStore datastore)
{
string[] scopes = new string[] {DirectoryService.Scope.AdminDirectoryUser };
try
{
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, datastore).Result; // at this point it calls getasynch method for custom datasource
DirectoryService service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "GoogleProv",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
{
HttpClientInitializer = credential,
ApplicationName = "GoogleProv",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
///<summary>
// Returns the stored value for the given key or <c>null</c> if the matching file (<see cref="GenerateStoredKey"/>
// in <see cref="FolderPath"/> doesn't exist.
// </summary>
// <typeparam name="T">The type to retrieve</typeparam>
// <param name="key">The key to retrieve from the data store</param>
// <returns>The stored object</returns>
public Task<T> GetAsync<T>(string key)
{
//Key is the user string sent with AuthorizeAsync
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
// Note: create a method for opening the connection.
SqlConnection myConnection = new SqlConnection(myconn);
myConnection.Open();
// Try and find the Row in the DB.
using (SqlCommand command = new SqlCommand("select RefreshToken from GoogleUser where UserName = #username;", myConnection))
{
command.Parameters.AddWithValue("#username", key);
string RefreshToken = null;
SqlDataReader myReader = command.ExecuteReader();
while (myReader.Read())
{
RefreshToken = myReader["RefreshToken"].ToString();
}
if (RefreshToken == null )
{
// we don't have a record so we request it of the user.
tcs.SetResult(default(T)); // it comes here
}
else
{
try
{
// we have it we use that.
tcs.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(RefreshToken));
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
}
return tcs.Task; // it comes here and than gets hang forever
}
Any of your help is highly appreciated.

HttpWebRequest maintenance and http web errors causing it to return "HRESULT E_FAIL" and "server not found"

I am iterating through a large list of objects (1503) and calling a save method on a ServiceProxy I have written. The service proxy uses the new networking stack in Silverlight 4 to call BeginGetRequestStream to start the process of asynchronously sending my objects to an azure REST service I have written for saving off the objects. The Http method I am using is POST. I know HttpWebClient is smart enough to reuse the Http connection so I am not concurrently opening 1503 connections to the server. Saving works fine and all 1503 objects are saved very quickly. However, when I try to save the same objects again, I expect to recieve an HttpStatus code of forbidden because the objects already exist and that is the code I set my azure web service to return. On small groups of objects, it works as expected. However, when I try saving the entire list of 1503 objects, I receive only 455 correct responses and 1048 errors such as "server not found" and
System.Exception ---> System.Exception:Error HRESULT E_FAIL has been returned from a call to a COM component.
at
System.Net.Browser.ClientHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)...
I wonder if there is some sort of book keeping or maintenance I am supposed to be performing on my HttpWebClient instances that I am neglecting and that is what is causing the http errors to throw exceptions but the new saves to work perfectly. Here is my code for handling the error cases:
private static void SendAncestorResponseCallback(IAsyncResult result)
{
var info = (SendAncestorInfo)result.AsyncState;
try
{
var response = info.Request.EndGetResponse(result);
info.Response = response;
}
catch ( Exception ex)
{
info.Error = ex;
}
info.MainThreadContext.Post(SendAncestorMainThreadCallback, info);
}
private static void SendAncestorMainThreadCallback(object state)
{
var info = (SendAncestorInfo)state;
IAncestor origAncestor = info.Content;
HttpWebResponse response = null;
if (info.Error != null)
{
if ((info.Error as WebException) == null)
{
info.Callback(false, origAncestor, null, info.Error);
return;
}
else //get response from WebException
{
response = (HttpWebResponse)(info.Error as WebException).Response;
}
}
else //get response from info.Response
{
response = info.Response as HttpWebResponse;
}
if (response.StatusCode == HttpStatusCode.Created || response.StatusCode == HttpStatusCode.Forbidden)
{
var stream = response.GetResponseStream();
using (var reader = new StreamReader(stream))
{
IAncestor retAncestor = XMLSerializerHelper.DeserializeObject<Ancestor>(reader.ReadToEnd());
info.Callback(response.StatusCode == HttpStatusCode.Created, origAncestor, retAncestor, null);
}
}
else info.Callback(false, origAncestor, null, info.Error);
}
considering how the web service is written I should only expect http status codes of created or forbidden and like I said with small groups this is the case. The fact that I only start getting the errors mentioned earlier makes me feel like I am doing something wrong with the HttpWebRequest objects etc. Any assistance would be greatly appreciated. Thanks.
--update here is the code that generates the HttpWebRequest:
foreach (IAncestor ancestor in ancestors)
{
AncestorViewModel ancestorVM = new AncestorViewModel(ancestor);
ancestorVM.Status = SaveStatus.Undefined;
ParsedAncestors.Add(ancestorVM);
_service.CreateAncestor(UserSrc, ancestor, (success, origAncestor, retAncestor, exception) =>
{
AncestorViewModel result = ParsedAncestors.First(a => a.Model.IdNo == origAncestor.IdNo);
if (exception == null)//web response was either Created or Forbidden
{
if (success)//Ancestor successfully created
{
savedAncestors++;
SuccessMessage = string.Format("{0} Saved\n", savedAncestors);
result.Status = SaveStatus.Saved;
}
else //Ancestor already existed
{
conflictAncestors.Add(origAncestor, retAncestor);
ConflictMessage = string.Format("{0} Conflicts\n", conflictAncestors.Count);
result.Status = SaveStatus.Conflicted;
}
}
else //Show exception recieved from remote web service
{
//if (exception as WebException != null)
//{
// //if exception is WebException get status code and description
// HttpWebResponse rs = (HttpWebResponse)(exception as WebException).Response;
// Message += string.Format("WebServer returned status code {0}: '{1}'\n", (int)rs.StatusCode, rs.StatusDescription);
//}
errors.Add(origAncestor, exception);
ErrorMessage = string.Format("{0} Errors\n", errors.Count);
result.Status = SaveStatus.Error;
}
});
}
public void CreateAncestor(string userSrc, IAncestor ancestor, Action<bool, IAncestor, IAncestor, Exception> callback)
{
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
var request = (HttpWebRequest)WebRequest.Create(
new Uri(string.Format("{0}/{1}/{2}", rootUri, AncestorsRestPoint, userSrc)));
request.Method = "POST";
request.ContentType = "application/xml";
var info = new SendAncestorInfo
{
Request = request,
Callback = callback,
Content = ancestor,
MainThreadContext = SynchronizationContext.Current
};
request.BeginGetRequestStream(SendAncestorRequestCallback, info);
}