FirebaseOptions options = new FirebaseOptions.Builder()
.setCredential(FirebaseCredentials.applicationDefault())
.setDatabaseUrl("https://mkastrive.firebaseio.com")
.build();
FirebaseApp defaultApp = FirebaseApp.initializeApp(options);
DatabaseReference ref = defaultDatabase
.getInstance()
.getReference("users");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("in onDataChange");
System.out.println(dataSnapshot.getValue());
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("in onCancelled");
System.out.println(databaseError.toString());
}
});
I'm doing the above in the Google Cloud Module in Android. I think my Firebase's initialization is successful because System.out.println("usersRef.push(): " + usersRef.push()); // Working
But I do not see anything for addListenerForSingleValueEvent. I do not see any error/warnings in the logs either. My database rules are set up for anyone to be able to read/write data.
Update 1: According to the suggestion on using setValue(), I tried the example on the firebase's documents:
DatabaseReference usersRef1 = ref.child("users");
Map<String, User> users = new HashMap<String, User>();
users.put("alanisawesome", new User("June 23, 1912", "Alan Turing"));
users.put("gracehop", new User("December 9, 1906", "Grace Hopper"));
usersRef1.setValue(users);
But this is not inserting in the database either, and also no errors. Log's blank.
Update 2:
Some logs
FirebaseApp defaultApp = FirebaseApp.initializeApp(options);
this.defaultDatabase = FirebaseDatabase.getInstance().getReference();
defaultDatabase.child("users").getPath(): https://mkastrive.firebaseio.com
defaultDatabase.child("users").getPath(): /users
Calling push() doesn't make any changes to the database. That's probably why your listener isn't being invoked. push() just returns a DatabaseReference that you can use to make changes at the location represented by that reference. The key of that location (the unique push id) is generated completely on the client.
Try actually writing a value to the database using setValue() on the DatabaseReference returned by push().
Related
I wanted to create cloud firestore database programmatically using c#, but I am getting error when I run the code. How would I fix permission related issue I am facing? Below is the code and error
private static AppengineService _appEngineService;
public static void IntializeAppEngine() {
GoogleCredential credential = GoogleCredential.GetApplicationDefault();
if (CloudManager.Credential.IsCreateScopedRequired)
{
credential = CloudManager.Credential.CreateScoped(
AppengineService.Scope.CloudPlatform);
}
_appEngineService = new AppengineService(
new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = CloudManager.ApplicationName
});
}
public static void AddCloudFirestore() {
IntializeAppEngine();
var body = new Application {
LocationId = "us-east1",
Id = "projects/" + CloudManager.ProjectId
};
var res = _appEngineService.Apps.Create(body).Execute();
}
Error:
Unhandled exception. The service appengine has thrown an exception.
HttpStatusCode is Forbidden.
Google.Apis.Requests.RequestError
The caller does not have permission [403]
Errors [
Message[The caller does not have permission] Location[ - ] Reason[forbidden] Domain[global]
]
Google.GoogleApiException: The service appengine has thrown an exception. HttpStatusCode is Forbidden. The caller does not have permission
at Google.Apis.Requests.ClientServiceRequest`1.ParseResponse(HttpResponseMessage response)
at Google.Apis.Requests.ClientServiceRequest`1.Execute()
at CloudResourceManager.FirebaseManagement.AddCloudFirestore()
Instead of Appengine, Cloud Firestore REST API can be used as Sarah suggested.
In c# Google.Apis.Firestore.v1 can be used to create cloud firestore.
AppEngine Objectify Java Unit Test gives a weird session cache error as described below.
Test Case:
private final LocalServiceTestHelper helper = new LocalServiceTestHelper(
new LocalDatastoreServiceTestConfig());
protected Closeable session;
#Before
public void setUp() throws Exception {
helper.setUp();
ObjectifyService.setFactory(new ObjectifyFactory());
ObjectifyService.register(UserData.class);
session = ObjectifyService.begin();
}
#After
public void tearDown() throws Exception {
session.close();
helper.tearDown();
}
#Test
public void testUserDataQuery throws Exception {
...
saveUserData();
...
getUserData();
...
}
Call 1:
UserData saveUserData {
...
UserData userData = (UserData) ofy().load().key(key).now();
...
// UserData is modified, the modifications are not stored in datastore,
// as those are temporary.
return userData;
}
Call 2:
UserData getUserData {
...
UserData userData = (UserData) ofy().load().key(key).now();
...
// Return the datastore saved UserData object.
return userData;
}
When the unit test case is executed, the modification done in saveUserData call is seen in getUserData query. Even though ofy().load() has been called, the UserData is not loaded from datastore instead served from the cached entry.
I have tried ofy().clear() call to clear the session cache. This is not avoid the error in all the cases.
This is happening only in Unit Test environment rather than in development or production server.
In the code you posted, yes you'll get the same object back - that's the way the session cache works. Clearing the session cache after save will indeed give you a new object loaded from the datastore (or memcache). But my guess is that this is not what you really want to test.
I'm wildly guessing that you are trying to simulate multiple backend calls in your test. IRL, each backend call will operate in its own server-side context. So what I recommend is creating a context for each call, using closures:
#Test
public void testUserDataQuery throws Exception {
...
req(() -> saveUserData());
...
req(() -> getUserData());
...
}
Where req() does the begin()/close() of the Objectify context (as well as any other request-specific processing your container usually does). You can leave the Objectify initialization in the before/after.
Context
My core goal is to write an Azure WebApps deployment tool in C#. The process will be roughly
User logs in
User selects subscription
User selects or creates resource group
User selects or creates storage for the web app
User selects or creates web service plan
User selects or creates web app
Tool uploads the web app using Kudu to POST a zip
Since the last step can't be done in the portal, my idea was to do everything in a GUI tool.
I started out using Kudu's ARMClient.Authentication and Microsoft.Azure.ResourceManager 1.0.0-preview. However, when it comes to creating a storage account I get a permissions error (The subscription is not registered to use namespace Microsoft.Storage), so my plan B was to do the authentication myself following Brady Gaster's blog post.
The problem
I've set up an application as documented, and using its clientId and tenantId I'm able to log in and list tenants. But I can't list any subscriptions. (NB I've partly elided the clientId and tenantId in case there are security risks with giving them in full).
string clientId = "f62903b9-ELIDED";
string tenantId = "47b6e6c3-ELIDED";
const string redirectUri = "urn:ietf:wg:oauth:2.0:oob";
const string baseAuthUri = "https://login.microsoftonline.com/";
const string resource = "https://management.core.windows.net/";
var ctx = new AuthenticationContext(baseAuthUri + tenantId);
var authResult = ctx.AcquireToken(resource, clientId, new Uri(redirectUri), PromptBehavior.Auto);
var token = new TokenCredentials(authResult.AccessToken);
var subClient = new SubscriptionClient(token);
var tenants = await subClient.Tenants.ListAsync();
foreach (var tenant in tenants) Console.WriteLine(tenant.TenantId);
var subs = await subClient.Subscriptions.ListAsync();
foreach (var sub in subs) Console.WriteLine(sub.DisplayName);
When I run this it prompts me to login, and lists the tenants corresponding to the subscriptions I own or co-administer. But it doesn't list a single subscription. If I change the IDs to the commonly used (I think officially for Powershell) values
clientId = "1950a258-227b-4e31-a9cf-717495945fc2";
tenantId = "common";
then it's the same.
What is the step I've missed in order to get a list of my subscriptions?
You need to iterate through the tenants, authenticate in tenant and get a subscription list for every tenant.
The following code will output the Subscriptions like Get-AzureRmSubscription powershell cmdlet does.
class Program
{
private static string m_resource = "https://management.core.windows.net/";
private static string m_clientId = "1950a258-227b-4e31-a9cf-717495945fc2"; // well-known client ID for Azure PowerShell
private static string m_redirectURI = "urn:ietf:wg:oauth:2.0:oob"; // redirect URI for Azure PowerShell
static void Main(string[] args)
{
try
{
var ctx = new AuthenticationContext("https://login.microsoftonline.com/common");
// This will show the login window
var mainAuthRes = ctx.AcquireToken(m_resource, m_clientId, new Uri(m_redirectURI), PromptBehavior.Always);
var subscriptionCredentials = new TokenCloudCredentials(mainAuthRes.AccessToken);
var cancelToken = new CancellationToken();
using (var subscriptionClient = new SubscriptionClient(subscriptionCredentials))
{
var tenants = subscriptionClient.Tenants.ListAsync(cancelToken).Result;
foreach (var tenantDescription in tenants.TenantIds)
{
var tenantCtx = new AuthenticationContext("https://login.microsoftonline.com/" + tenantDescription.TenantId);
// This will NOT show the login window
var tenantAuthRes = tenantCtx.AcquireToken(
m_resource,
m_clientId,
new Uri(m_redirectURI),
PromptBehavior.Never,
new UserIdentifier(mainAuthRes.UserInfo.DisplayableId, UserIdentifierType.RequiredDisplayableId));
var tenantTokenCreds = new TokenCloudCredentials(tenantAuthRes.AccessToken);
using (var tenantSubscriptionClient = new SubscriptionClient(tenantTokenCreds))
{
var tenantSubscriptioins = tenantSubscriptionClient.Subscriptions.ListAsync(cancelToken).Result;
foreach (var sub in tenantSubscriptioins.Subscriptions)
{
Console.WriteLine($"SubscriptionName : {sub.DisplayName}");
Console.WriteLine($"SubscriptionId : {sub.SubscriptionId}");
Console.WriteLine($"TenantId : {tenantDescription.TenantId}");
Console.WriteLine($"State : {sub.State}");
Console.WriteLine();
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
Console.WriteLine("press something");
Console.ReadLine();
}
}
}
A couple things you can look into...
1) the error you saw during creating of the storage account is likely due to the Resource Provider not being registered for use with the subscription. Any RP needs to be registered before use, some clients (Portal, PowerShell) will register the RP for you so you never notice it. See: https://msdn.microsoft.com/en-us/library/azure/dn790548.aspx - you should be able to do that from your code if the user has sufficient perms.
2) You may not be getting any subscriptions back because your endpoint (management.core.windows.net) is the endpoint for Azure Service Management not Azure Resource Manager (management.azure.com). If the subscription access is granted via AzureRM and RBAC, the old ASM apis will not see (i.e. have access to) those subscriptions.
I'm having trouble following the second step here.
I really don't understand how this sample does anything other than return a simple toast message. How does it utilize the API to display that message?
class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
private static MyApi myApiService = null;
private Context context;
#Override
protected String doInBackground(Pair<Context, String>... params) {
if(myApiService == null) { // Only do this once
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// options for running against local devappserver
// - 10.0.2.2 is localhost's IP address in Android emulator
// - turn off compression when running against local devappserver
.setRootUrl("http://10.0.2.2:8080/_ah/api/")
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
#Override
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
// end options for devappserver
myApiService = builder.build();
}
context = params[0].first;
String name = params[0].second;
try {
return myApiService.sayHi(name).execute().getData();
} catch (IOException e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(context, result, Toast.LENGTH_LONG).show();
}
I'm afraid my this sample is too complex for my limited knowledge. How exactly do I "talk" to the Google Endpoints Module when running an app? Specifically, What is EndpointsAsyncTask();?
Are there any resources listing all the methods available to me? Is there a simpler example of an app communicating with a Google Cloud Endpoint?
The service methods available to you are defined by the backend source in section 1.
In the example you posted, this line: myApiService.sayHi(name).execute()
is an actual invocation call to the backend that you defined by annotating #ApiMethod("sayHi") on the method in the MyEndpoint.java class of your backend module.
The reason your Android app defines an EndpointsAsyncTask is because slow operations such as calls that hit the network need to happen off of the UI thread to avoid locking the UI. The demo simply puts the returned value into a Toast but you could modify onPostExecute() to do whatever you'd like with the result.
For more info on Google Endpoints check out:
https://cloud.google.com/appengine/docs/java/endpoints/
And for info about using an Android AsyncTask look here:
http://developer.android.com/reference/android/os/AsyncTask.html
Good morning I'm trying to integrate the Google+ Domains API with my company domain but I'm facing some problems.
I'm trying the java approach following the quick start for java but after implement the code the response from the google server is :
Authenticate the domain for hugo.catarino#outsystems.com
Inserting activity
10/Set/2013 17:08:49 com.google.api.client.googleapis.services.AbstractGoogleClient <init>
WARNING: Application name is not set. Call Builder#setApplicationName.
Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException:400 Bad Request
{
"error" : "access_denied"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:269)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:858)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.google.plus.samples.quickstart.domains.DomainDelegation.main(DomainDelegation.java:160)
here is used authentication method and my variables:
private static final String SERVICE_ACCOUNT_EMAIL = "638852846577#developer.gserviceaccount.com";
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH =
"src/com/google/plus/samples/quickstart/domains/05cab8e819cbd0a747b180c1f22fc93dba916b7b-privatekey.p12";
private static final String USER_EMAIL = "hugo.catarino#outsystems.com";
private static Plus authenticate() throws GeneralSecurityException, IOException {
System.out.println(String.format("Authenticate the domain for %s", USER_EMAIL));
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
// Setting the sub field with USER_EMAIL allows you to make API calls using the special keyword
// 'me' in place of a user id for that user.
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(SCOPE)
.setServiceAccountUser(USER_EMAIL)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH)).build();
// Create and return the Plus service object
Plus service = new Plus.Builder(httpTransport, jsonFactory, credential).build();
return service;
}
My main class has the following code like in the sample:
Plus service = authenticate();
String userId = "me";
String msg = "Happy Monday! #caseofthemondays";
System.out.println("Inserting activity");
// Create the audience of the post
PlusAclentryResource res = new PlusAclentryResource();
// Share to the domain
res.setType("domain");
List<PlusAclentryResource> aclEntries = new ArrayList<PlusAclentryResource>();
aclEntries.add(res);
Acl acl = new Acl();
acl.setItems(aclEntries);
// Required, this does the domain restriction
acl.setDomainRestricted(true);
Activity activity = new Activity()
.setObject(new Activity.PlusObject().setOriginalContent(msg))
.setAccess(acl);
activity = service.activities().insert(userId, activity).execute();
System.out.println(activity);
In domain cPanel the company defined for me the next scopes:
https://www.googleapis.com/auth/plus.circles.read
https://www.googleapis.com/auth/plus.circles.write
https://www.googleapis.com/auth/plus.me
https://www.googleapis.com/auth/plus.media.upload
https://www.googleapis.com/auth/plus.stream.read
https://www.googleapis.com/auth/plus.stream.write
My scope definition is:
private static final List<String> SCOPE = Arrays.asList(
"https://www.googleapis.com/auth/plus.circles.read",
"https://www.googleapis.com/auth/plus.circles.write",
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.media.upload",
"https://www.googleapis.com/auth/plus.stream.read",
"https://www.googleapis.com/auth/plus.stream.write");
I'm a bit lost here , is there any way of debug this problem or know why is this access denied?
There are several things that you should check.
First, is the private key file that you downloaded from the Google APIs Console in the correct path with your code? This file is referenced by the following variable. This needs to tell the OAuth client library where to find the file.
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH =
"/path/to/<public_key_fingerprint>-privatekey.p12";
It is very important that you do not rename the file.
Second, does your scope list in your code match the list of scopes set in the Admin console?
The configuration in the Admin console for your Google Apps domain, and the scopes provided in the request must be identical. Try adjusting the SCOPE variable in your code to be:
private static final List<String> SCOPE = Arrays.asList(
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.circles.read",
"https://www.googleapis.com/auth/plus.circles.write",
"https://www.googleapis.com/auth/plus.media.upload",
"https://www.googleapis.com/auth/plus.stream.read",
"https://www.googleapis.com/auth/plus.stream.write");
In general, it is best to only request the scopes that you will need, rather than all scopes available.
Third, make sure that the client ID you generated is the one listed on the Admin console entry that specifies the scopes permitted.