GAE - No API environment is registered for this thread - firebase

I have an spring-boot application deployed to google cloud using google app engine. There is a datastore with multiple entities.
When I try to retrieve data through my app (app is uploaded to appengine, not locally) it always throws an error -
There was an unexpected error (type=Internal Server Error, status=500).
No API environment is registered for this thread.
I am trying to make it work this way:
#Bean
public FirebaseAuth firebaseAuth() throws IOException {
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream
serviceAccount = classLoader.getResourceAsStream("downloaded-key-270620-2a16da8f4062.json");
FirebaseOptions options = (new Builder())
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl(
"https://my-app.firebaseio.com")
.build();
FirebaseApp.initializeApp(options);
return FirebaseAuth.getInstance();
}
private Result<Product> list(boolean wholesale, String startCursorString) {
FetchOptions fetchOptions = Builder.withLimit(10);
if (startCursorString != null && !startCursorString.equals("")) {
fetchOptions.startCursor(Cursor.fromWebSafeString(startCursorString));
}
Query query = (new Query("Product")).setFilter(
new FilterPredicate("wholesale", FilterOperator.EQUAL, wholesale))
.addSort("name", SortDirection.ASCENDING);
PreparedQuery preparedQuery = this.datastore.prepare(query);
QueryResultIterator<Entity> results = preparedQuery.asQueryResultIterator(fetchOptions);
List<Product> resultBooks = this.entitiesToObjects(results);
Cursor cursor = results.getCursor();
if (cursor != null && resultBooks.size() == 10) {
String cursorString = cursor.toWebSafeString();
return new Result(resultBooks, cursorString);
} else {
return new Result(resultBooks);
}
}
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.GET, new String[] { "/products" })
.antMatchers(HttpMethod.GET, new String[] { "/purchases/update" })
.antMatchers(HttpMethod.GET, new String[] { "/purchases/statistics/**" });
}
Any idea what could be the problem?

I think you might be missing inizialiting it according to the documentation, it would be something like:
Datastore datastore = DatastoreOptions.getDefaultInstance().getService();

Related

AspNetIdentityDocumentDB and Cross partition query is required but disabled

I have an app that uses CosmosDb as the database and using AspNetIdentityDocument. When I call var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, false), i get the error Cross partition query is required but disabled. Please set x-ms-documentdb-query-enablecrosspartition to true, specify x-ms-documentdb-partitionkey
void InitializeDocumentClient(DocumentClient client) code attempts to create the container if not there. It works for the creating the container on my CossmosDb emultated store but fails on the Azure store requiring a partition key! My app works on the emulated store!
Program.cs
builder.Services.AddDefaultDocumentClientForIdentity(
builder.Configuration.GetValue<Uri>("DocumentDbClient:EndpointUri"),
builder.Configuration.GetValue<string>("DocumentDbClient:AuthorizationKey"),
afterCreation: InitializeDocumentClient);
builder.Services.AddIdentity<ApplicationUser, DocumentDbIdentityRole>()
.AddDocumentDbStores(options =>
{
options.UserStoreDocumentCollection = "AspNetIdentity";
options.Database = "RNPbooking";
})
.AddDefaultTokenProviders();
void InitializeDocumentClient(DocumentClient client)
{
try
{
var db = client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri("RNPbooking")).Result;
}
catch (AggregateException ae)
{
ae.Handle(ex =>
{
if (ex.GetType() == typeof(DocumentClientException) && ((DocumentClientException)ex).StatusCode == HttpStatusCode.NotFound)
{
var db = client.CreateDatabaseAsync(new Microsoft.Azure.Documents.Database() { Id = "RNPbooking" }).Result;
return true;
}
return false;
});
}
try
{
var collection = client.ReadDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri("RNPbooking", "AspNetIdentity")).Result;
}
catch (AggregateException ae)
{
ae.Handle(ex =>
{
if (ex.GetType() == typeof(DocumentClientException) && ((DocumentClientException)ex).StatusCode == HttpStatusCode.NotFound)
{
DocumentCollection collection = new DocumentCollection()
{
Id = "AspNetIdentity"
};
collection = client.CreateDocumentCollectionAsync(UriFactory.CreateDatabaseUri("RNPbooking"),collection).Result;
return true;
}
return false;
});
}
}
Controller
[Authorize(Roles = "Admin)]
public class AdminController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public CosmosClient _client;
public AdminController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
)
{
_userManager = userManager;
_signInManager = signInManager;
}
You need to fill in CreateDocumentCollectionUri method with FeedOptions object as a parameter
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),new FeedOptions { EnableCrossPartitionQuery=true})
UPDATED: From the code examples, you seem to be using this library https://github.com/codekoenig/AspNetCore.Identity.DocumentDb, AspNetCore.Identity.DocumentDb.
This error means the library you are using is performing a Document Query in their code at some point, it is not related to the creation of the Database or Collection.
The library code must be using CreateDocumentQuery somewhere, that code is missing:
new FeedOptions { EnableCrossPartitionQuery = true };
If you search their code base, you will see multiple scenarios like that: https://github.com/codekoenig/AspNetCore.Identity.DocumentDb/search?q=CreateDocumentQuery
Because this code is out of your control, you should try and contact the owner to see if this is a fix they can do on their end. The code for the library doesn't seem to have been updated in several years, so maybe this library is not maintained?

OIDC Client LoginAsync in Xamarin App iOS never returns result

I have a Xamarin iOS application I am building. For the Authentication and Authorization I am using Identity Server. To logon I am using IdentityModel.OidcClient using version 4.0.0.
When a user click on a Login button I call the Identity Server using:
_result = await _client.LoginAsync(new LoginRequest());
I am redirected to my identity server and can succesfully login. After login the browser disappears but the code never reaches the next line:
_result = await _client.LoginAsync(new LoginRequest());
if (_result.IsError)
{
return;
}
I have found many example and they all tell me to do the following. I have also tried with the demo Identity Server and same issue.
This is the IdentityModel.OidcClient.Browser.IBrowser implementation:
public class ASWebAuthenticationSessionBrowser : IBrowser
{
ASWebAuthenticationSession _asWebAuthenticationSession;
public ASWebAuthenticationSessionBrowser()
{
Debug.WriteLine("ctor");
}
public Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
{
var tcs = new TaskCompletionSource<BrowserResult>();
try
{
_asWebAuthenticationSession = new ASWebAuthenticationSession(
new NSUrl(options.StartUrl),
new NSUrl(options.EndUrl).Scheme,
(callbackUrl, error) =>
{
tcs.SetResult(CreateBrowserResult(callbackUrl, error));
_asWebAuthenticationSession.Dispose();
});
// iOS 13 requires the PresentationContextProvider set
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
_asWebAuthenticationSession.PresentationContextProvider = new PresentationContextProviderToSharedKeyWindow();
_asWebAuthenticationSession.Start();
}
catch (Exception ex)
{
throw;
}
return tcs.Task;
}
class PresentationContextProviderToSharedKeyWindow : NSObject, IASWebAuthenticationPresentationContextProviding
{
public UIWindow GetPresentationAnchor(ASWebAuthenticationSession session)
{
return UIApplication.SharedApplication.KeyWindow;
}
}
private static BrowserResult CreateBrowserResult(NSUrl callbackUrl, NSError error)
{
if (error == null)
return new BrowserResult
{
ResultType = BrowserResultType.Success,
Response = callbackUrl.AbsoluteString
};
if (error.Code == (long)ASWebAuthenticationSessionErrorCode.CanceledLogin)
return new BrowserResult
{
ResultType = BrowserResultType.UserCancel,
Error = error.ToString()
};
return new BrowserResult
{
ResultType = BrowserResultType.UnknownError,
Error = error.ToString()
};
}
}
I am using Xamarin.Forms and netstandard 2.0.
My redirect uri: RedirectUri = "wodtracker.app://callback"

Application Insights configuration web API

I have created a library project for writing logs into ApplicationInsights as well as table storage and is being consumed my different other WebAPI projects. But due to some reason the logs are not getting logged in Application Insights but it works with table storage.
private void AddTelemetryTarget(string instrumentationKey, LoggerEnumerations.LogLevel minLogLevel, LoggingConfiguration config)
{
try
{ ConfigurationItemFactory.Default.Targets.RegisterDefinition("ApplicationInsightsTarget", typeof(ApplicationInsightsTarget));
ApplicationInsightsTarget aiTarget = new ApplicationInsightsTarget();
aiTarget.InstrumentationKey = instrumentationKey;
aiTarget.Name = "ai";
var wrapper = new AsyncTargetWrapper(aiTarget, 5000, AsyncTargetWrapperOverflowAction.Grow);
config.AddTarget("TelemetryAsyncWrapper", wrapper);
//Applying logging rules.
LoggingRule rule = new LoggingRule("*", ConvertLogType(minLogLevel), aiTarget);
config.LoggingRules.Add(rule);
}
catch
{ }
}
private LogLevel ConvertLogType(LoggerEnumerations.LogLevel type)
{
switch (type)
{
case LoggerEnumerations.LogLevel.Error: return LogLevel.Error;
case LoggerEnumerations.LogLevel.Info: return LogLevel.Info;
case LoggerEnumerations.LogLevel.Warn: return LogLevel.Warn;
default: return LogLevel.Trace;
}
}
public async Task Log(string message, LoggerEnumerations.LogLevel type, Dictionary<string, string> customParams, Exception ex = null, bool isPayload = false)
{
LogEventInfo eventInfo = PopulateEventInfo(message, type, customParams, ex);
if (!isPayload)
{
_logger.Log(eventInfo);
}
else
{
_payloadLogger.Log(eventInfo);
}
}
private LogEventInfo PopulateEventInfo(string message, LoggerEnumerations.LogLevel type, Dictionary<string, string> customParams, Exception ex = null)
{
LogEventInfo eventInfo = new LogEventInfo();
eventInfo.Level = ConvertLogType(type);
eventInfo.Message = message;
eventInfo.LoggerName = this.GetType().ToString();
if (ex != null)
{
eventInfo.Exception = ex;
}
else if (eventInfo.Level == LogLevel.Error)
{
eventInfo.Exception = new Exception(message);
}
//Adding custom properties to LogEventInfo to display in Application insight
if (customParams != null)
{
foreach (KeyValuePair<string, string> param in customParams)
{
eventInfo.Properties.Add(param.Key, param.Value);
}
}
return eventInfo;
}
Version of Nuget packages are
Microsoft.ApplicationInsights.NLogTarget : 2.13.1
NLog : 4.6.8
Thanks
I added Application Insights as Connected Services and I removed the Instrumentation Key from ApplicationInsights.config file and when registering the nlog target I used instrumentation key from my web.config file and it started working.

Google.Apis.Requests.RequestError Not Found when deleting event

I have below method to delete event in calendar:
public async Task<string> DeleteEventInCalendarAsync(TokenResponse token, string googleUserId, string calendarId, string eventId)
{
string result = null;
try
{
if (_calService == null)
{
_calService = GetCalService(token, googleUserId);
}
// Check if event exist
var eventResource = new EventsResource(_calService);
var erListRequest = eventResource.List(calendarId);
var eventsResponse = await erListRequest.ExecuteAsync().ConfigureAwait(false);
var existingEvent = eventsResponse.Items.FirstOrDefault(e => e.Id == eventId);
if (existingEvent != null)
{
var deleteRequest = new EventsResource.DeleteRequest(_calService, calendarId, eventId);
result = await deleteRequest.ExecuteAsync().ConfigureAwait(false);
}
}
catch (Exception exc)
{
result = null;
_logService.LogException(exc);
}
return result;
}
And I am getting error as follow -
Google.GoogleApiException Google.Apis.Requests.RequestError Not Found [404] Errors [ Message[Not Found] Location[ - ] Reason[notFound] Domain[global] ]
Can you help me understand why this error? Or where I can find the details about these error?
The error you are getting is due to the event's id you are passing doesn't exist or you are passing it in the wrong way. Following the .Net Quickstart I made a simple code example on how to pass the event's id to the Delete(string calendarId, string eventId) method from the Class Events
namespace CalendarQuickstart
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-dotnet-quickstart.json
static string[] Scopes = { CalendarService.Scope.Calendar };
static string ApplicationName = "Google Calendar API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Google Calendar API service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define request.
EventsResource.ListRequest request = service.Events.List("primary");
// List events.
Events events = request.Execute();
Event existingEvent = events.Items.FirstOrDefault(e => e.Id == "your event id you want to get");
Console.WriteLine("Upcoming events:");
if (existingEvent != null)
{
Console.WriteLine("{0} {1}", existingEvent.Summary, existingEvent.Id);
string deleteEvent = service.Events.Delete("primary", existingEvent.Id).Execute();
}
else
{
Console.WriteLine("No upcoming events found.");
}
Console.Read();
}
}
}
Notice
I made this example in a synchronous syntax way for testing purposes in the console. After you test it and see how it works, you could adapt it to your code. Remember, make your you are passing the correct Id.
Docs
For more info check this doc:
Namespace Google.Apis.Calendar.v3

Azure AD SSO in ASP.NET - How to update token silently?

I have a quite simple ASP.NET project that has the Azure AD Authentication installed.
It uses the CookieAuthentication by default and uses the Azure AD SSO to login.
So what I can't understand is that if I login and left the page opened for 1 hour - which is the Azure AD access token expiration time, it just stops working.
To avoid this, I tried to update the access token silently before it is expired but failed.
Not even sure why the app stops working as it's using Cookie for authorization and it uses the Azure AD login only for Authentication.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = (context) =>
{
var threshold = DateTime.UtcNow.AddMinutes(55);
if (context.Properties.ExpiresUtc < threshold)
{
var authManager = context.OwinContext.Authentication;
string signedInUserID = context.Identity.FindFirst(System.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value;
if (authContext == null)
authContext = new AuthenticationContext(Authority, new ADALTokenCache(signedInUserID));
ClientCredential credential = new ClientCredential(clientId, appKey);
try
{
var result = authContext.AcquireTokenSilentAsync(graphResourceId, clientId).Result;
}
catch (AggregateException ex)
{
if (ex.InnerException.GetType() == typeof(AdalSilentTokenAcquisitionException))
{
var result = authContext.AcquireTokenAsync(graphResourceId, credential).Result;
}
}
}
return Task.FromResult(0);
}
}
});
This is the ADALTokenCache.
public class ADALTokenCache : TokenCache
{
private ApplicationDbContext db = new ApplicationDbContext();
private string userId;
private UserTokenCache Cache;
public ADALTokenCache(string signedInUserId)
{
// Associate the cache to the current user of the web app
userId = signedInUserId;
this.AfterAccess = AfterAccessNotification;
this.BeforeAccess = BeforeAccessNotification;
this.BeforeWrite = BeforeWriteNotification;
// Look up the entry in the database
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
// Place the entry in memory
this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits,"ADALCache"));
}
// Clean up the database
public override void Clear()
{
base.Clear();
var cacheEntry = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
db.UserTokenCacheList.Remove(cacheEntry);
db.SaveChanges();
}
// Notification raised before ADAL accesses the cache.
// This is your chance to update the in-memory copy from the DB, if the in-memory version is stale
void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
if (Cache == null)
{
// First time access
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
}
else
{
// Retrieve last write from the DB
var status = from e in db.UserTokenCacheList
where (e.webUserUniqueId == userId)
select new
{
LastWrite = e.LastWrite
};
// If the in-memory copy is older than the persistent copy
if (status.First().LastWrite > Cache.LastWrite)
{
// Read from from storage, update in-memory copy
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
}
}
this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache"));
}
// Notification raised after ADAL accessed the cache.
// If the HasStateChanged flag is set, ADAL changed the content of the cache
void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// If state changed
if (this.HasStateChanged)
{
Cache = new UserTokenCache
{
webUserUniqueId = userId,
cacheBits = MachineKey.Protect(this.Serialize(), "ADALCache"),
LastWrite = DateTime.Now
};
// Update the DB and the lastwrite
db.Entry(Cache).State = Cache.UserTokenCacheId == 0 ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
this.HasStateChanged = false;
}
}
void BeforeWriteNotification(TokenCacheNotificationArgs args)
{
// If you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
var t = args;
}
public override void DeleteItem(TokenCacheItem item)
{
base.DeleteItem(item);
}
}
This is what I tried, but not working.
Would appreciate any help.
Thanks in advance.

Resources