Android Firebase : Second Connected Database not allowing auth in rules - java

I've connected two Databases from the same firebase project like below.
//init the default db;
FirebaseApp.initializeApp(this);
//init the second db;
FirebaseOptions.Builder builder = new FirebaseOptions.Builder();
builder.setApplicationId("id"); //Same as default
builder.setApiKey("key"); //Same as default
builder.setDatabaseUrl("https://second-db.firebaseio.com");
try {
FirebaseApp.initializeApp(this, builder.build(), "second-db");
} catch (IllegalStateException e) {
e.printStackTrace();
}
Getting Reference.
public static DatabaseReference getSecondDbRef(String child) {
FirebaseApp app = FirebaseApp.getInstance("second-db");
return FirebaseDatabase.getInstance(app).getReference(child);
}
With the above, it works, but the rules in the second database don't seem to be getting auth. if I do.
{
"rules":{
"users":{
"$uid":{
".read":"auth.uid !== null",
// ".read":true // This works, so the issue is auth
}
}
}
}
The read fails, even though the user is authenticated, also, this problem isn't there with the default database. Is there anything I'm missing with the init?
Ok, because of highlights below, here's the code as it is on the app.
private static final String TEAMS_BD_ID = "second-db"
public void initFirebase() {
FirebaseApp.initializeApp(this);
FirebaseOptions.Builder builder = new FirebaseOptions.Builder();
builder.setApplicationId("appId"); // //Same as default
builder.setApiKey("key"); // //Same as default
builder.setDatabaseUrl("https://teams-db.firebaseio.com");//Second Db
try {
FirebaseApp.initializeApp(this, builder.build(), TEAMS_BD_ID);
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public static FirebaseApp getTeamsApp() {
return FirebaseApp.getInstance(TEAMS_BD_ID);
}
public static String getTeamsUserUid() {
return FirebaseAuth.getInstance(getTeamsApp()).getCurrentUser().getUid();
}
public static DatabaseReference getTeamsRef(String child) {
return FirebaseDatabase.getInstance(getTeamsApp()).getReference(child);
}
public static DatabaseReference getTeamsRef() {
return FirebaseDatabase.getInstance(getTeamsApp()).getReference();
}
Then trying to read.
DatabaseReference r = getTeamsRef().child("users/" + getTeamsUserUid() + "/teams")
// getTeamsUserUid() This is null.

It is only a guess.
If you are using FirebaseAuth#getInstance() for getting auth instance, change it to FirebaseAuth#getInstance(FirebaseApp firebaseApp) with the second app instance.

Related

How do I connect the java sdk to qldb?

I try this tutorial
https://docs.aws.amazon.com/qldb/latest/developerguide/getting-started.java.step-2.html but I don't understand how to connect to qldb with the java sdk.
I only need to update a document, but this documentation is so complex. Does anyone have any idea? Or something for dummies.
public final class ConnectToLedger {
public static final Logger log = LoggerFactory.getLogger(ConnectToLedger.class);
public static AWSCredentialsProvider credentialsProvider;
public static String endpoint = null;
public static String ledgerName = Constants.LEDGER_NAME;
public static String region = null;
public static PooledQldbDriver driver = createQldbDriver();
private ConnectToLedger() { }
/**
* Create a pooled driver for creating sessions.
*
* #return The pooled driver for creating sessions.
*/
public static PooledQldbDriver createQldbDriver() {
AmazonQLDBSessionClientBuilder builder = AmazonQLDBSessionClientBuilder.standard();
if (null != endpoint && null != region) {
builder.setEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region));
}
if (null != credentialsProvider) {
builder.setCredentials(credentialsProvider);
}
return PooledQldbDriver.builder()
.withLedger(ledgerName)
.withRetryLimit(Constants.RETRY_LIMIT)
.withSessionClientBuilder(builder)
.build();
}
/**
* Connect to a ledger through a {#link QldbDriver}.
*
* #return {#link QldbSession}.
*/
public static QldbSession createQldbSession() {
return driver.getSession();
}
public static void main(final String... args) {
try (QldbSession qldbSession = createQldbSession()) {
log.info("Listing table names ");
for (String tableName : qldbSession.getTableNames()) {
log.info(tableName);
}
} catch (QldbClientException e) {
log.error("Unable to create session.", e);
}
}
}
I'm sorry the documentation is complex. Here is a minimal version of the code you referred to with all the customization and options stripped out. It assumes your environment is setup to use the correct AWS region and credentials.
PooledQldbDriver driver = PooledQldbDriver.builder()
.withLedger("my-ledger-name")
.withSessionClientBuilder(AmazonQLDBSessionClientBuilder.standard())
.build();
try (QldbSession session = driver.getSession()) {
session.execute("UPDATE my-table SET my-field = ?", < Ion value here >);
}
I'd love to help you further, but your question as it stands doesn't make it clear where you got stuck. For example, did you try run the above code and, if so, did you get an error? If you update your question with more information or respond to my answer in the comments I"ll check back in.
so i reduce the code because the example need more experience on QLDB sdk java, and java.
public QldbSession getQldbSession(String ledgerName) {
final AmazonQLDBSessionClientBuilder builder = AmazonQLDBSessionClientBuilder.standard();
if (null != endpoint && null != region) {
builder.setEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region));
}
if (null != credentialsProvider) {
builder.setCredentials(credentialsProvider);
}
final PooledQldbDriver driver = PooledQldbDriver.builder().withLedger(ledgerName).withRetryLimit(4)
.withSessionClientBuilder(builder).build();
return driver.getSession();
}
Result result = null;
try {
final String query = "!query hereĀ”";
final IonObjectMapper MAPPER = new IonValueMapper(IonSystemBuilder.standard().build());
final List<IonValue> parameters = new ArrayList<>();
parameters.add(MAPPER.writeValueAsIonValue("parameter"));
parameters.add(MAPPER.writeValueAsIonValue("parameter"));
parameters.add(MAPPER.writeValueAsIonValue("parameter"));
result = qldbSession.execute(query, parameters);
} catch (final QldbClientException e) {
System.out.println("Unable to create session.");
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}

Retrofit Task (Execute) Called from another function doesn't wait until Task finish

From my Login Activity (First Activity Opened) I always do a check if the token is still active on my server which is done through Async Task that does API call to server.
here's the code from LoginActivity :
private void checkIfAuthenticated(){
SharedPreferences reader_auth = getSharedPreferences(getString(R.string.auth_preferences), MODE_PRIVATE);
String auth_key = reader_auth.getString(getString(R.string.auth_access_key),null);
String mobile_token = reader_auth.getString(getString(R.string.auth_mobile_token),null);
if (auth_key != null) {
//THIS PART RUNS THE TOKEN CHECK TO SERVER
authGlobal = new AuthenticationGlobal(this);
// I WANT THIS FUNCTION TO FINISH FIRST BEFORE IT GOES TO THE NEXT PART OF THE CODE
authGlobal.runAuthenticationCheck(auth_key,mobile_token);
String Auth_Key = reader_auth.getString(getString(R.string.auth_access_key),null);
Log.d("Auth Key Check 0",Auth_Key);
if (Auth_Key != null) {
Log.d("Auth Key Check 1",Auth_Key);
MoveToDashboardActivity();
}
}
}
The runAuthenticationCheck(String,String) Code is located on another class (Because it was meant to be a global function which can be called from any function on any activity)
runAuthenticationCheck is located in AuthenticationGlobal Class, here's the code :
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
checkAuthTask.execute((Void) null);
}
public class checkAuthenticationTask extends AsyncTask<Void, Void, Boolean> {
private GetDataService service;
private String mobile_token;
private String access_token;
checkAuthenticationTask( String Access_token,String Mobile_token) {
/*Create handle for the RetrofitInstance interface*/
mobile_token = Mobile_token;
access_token = Access_token;
service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
}
#Override
protected Boolean doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
try {
Call<CheckAuthenticationResponse> call = service.checkAuthentication(access_token,mobile_token);
Response<CheckAuthenticationResponse> CheckAuthenticationResponse = call.execute();
if (CheckAuthenticationResponse.code() == 200){
} else{
//clear shared preferences
clearAuthentication();
Log.e("AuthKey Global","Expired0");
}
} catch (IOException ea) {
clearAuthentication();
Log.e("AuthKey Global","Expired1");
Log.e("AuthenticationResponseError Global","Network Went Wrong");
ea.printStackTrace();
}
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
//mAuthTask = null;
//showProgress(false);
if (success) {
Log.e("AuthKey Global","Done");
} else {
// mPasswordView.setError(getString(R.string.error_incorrect_password));
clearAuthentication();
Log.e("AuthKey Global","Expired2");
}
}
#Override
protected void onCancelled() {
//mAuthTask = null;
//showProgress(false);
}
There are 2 Class / Activity : "LoginActivity" and "AuthenticationGlobal".
There are 3 Function :
checkIfAuthenticated => located in LoginActivity, Which in turn actually call another function from another class (Function number 2 : "runAuthenticationCheck")
runAuthenticationCheck => located in AuthenticationGlobal. which in calls a AsyncTask via .execute(...) command.
checkAuthenticationTask => located in AuthenticationGlobal. Which actually does the API Call to server.
From "LoginActivity" I run a function "checkIfAuthenticated" => which calls function "runAuthenticationCheck" located at "AuthenticationGlobal" => which runs a Task "checkAuthenticationTask" which does API Call to server and does stuff.
The problem is, when I called the first Function, the code doesn't wait until the function "checkIfAuthenticated" / "checkAuthenticationTask" is done. Is there a way for me to make the app wait until the task / function finish first??
Thank you
UPDATE :
I ONLY NEED TO ADD .get() at the end of .execute() and wrap it inside try catch.
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
try {
checkAuthTask.execute((Void) null).get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Well. I just need to add a .get() on the execute() and wrap it inside a try catch.
A dumb mistake.
here's the updated code :
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
try {
checkAuthTask.execute((Void) null).get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

why am i getting an error on .verifyCredentials()

I want to get the data using twitter's fabric api but whenever i tend to verify credentials and use a callback it shows an error , specifically ,"The arguments differ in length"
void getUserData() {
Twitter.getApiClient(session).getAccountService()
.verifyCredentials(true, false, new Callback<User>() {
#Override
public void failure(TwitterException e) {
}
#Override
public void success(Result<User> userResult) {
User user = userResult.data;
String twitterImage = user.profileImageUrl;
try {
Log.d("imageurl", user.profileImageUrl);
Log.d("name", user.name);
Log.d("email",user.email);
Log.d("des", user.description);
Log.d("followers ", String.valueOf(user.followersCount));
Log.d("createdAt", user.createdAt);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
If you check the fabric documentation, it shows two version of the method, however when I tried to open the source code in Android Studio but it had only the version without the callback.
You can solve the isssue as follows:
//Getting the account service of the user logged in
Call<User> call = Twitter.getApiClient(session).getAccountService()
.verifyCredentials(true, false);
call.enqueue(new Callback<User>() {
#Override
public void failure(TwitterException e) {
//If any error occurs handle it here
}
#Override
public void success(Result<User> userResult) {
//If it succeeds creating a User object from userResult.data
User user = userResult.data;
String twitterImage = user.profileImageUrl;
try {
Log.d("imageurl", user.profileImageUrl);
Log.d("name", user.name);
Log.d("email",user.email);
Log.d("des", user.description);
Log.d("followers ", String.valueOf(user.followersCount));
Log.d("createdAt", user.createdAt);
} catch (Exception e) {
e.printStackTrace();
}
}
});
Source
Documentation
Just change the twitter dependency in your Build.Gradle
from
compile('com.twitter.sdk.android:twitter:2.0.0#aar') {
transitive = true;
}
to
compile('com.twitter.sdk.android:twitter:1.11.0#aar') {
transitive = true;
}
The new version of the .verifyCredentials() method doesn't accept a callback hence your error.

Whats the Best Practice to call a method out of a Callback-Response?

I'm using an asyncronus XML-RPC-Client (https://github.com/gturri/aXMLRPC) in my Project and wrote some methods using the asyncronous Callback-Methods of this Client like this this:
public void xmlRpcMethod(final Object callbackSync) {
XMLRPCCallback listener = new XMLRPCCallback() {
public void onResponse(long id, final Object result) {
// Do something
if (callbackSync != null) {
synchronized (callbackSync) {
callbackSync.notify();
}
}
}
public void onError(long id, final XMLRPCException error) {
// Do something
if (callbackSync != null) {
synchronized (callbackSync) {
callbackSync.notify();
}
}
}
public void onServerError(long id, final XMLRPCServerException error) {
Log.e(TAG, error.getMessage());
if (callbackSync != null) {
synchronized (callbackSync) {
callbackSync.notifyAll();
}
}
}
};
XMLRPCClient client = new XMLRPCClient("<url>");
long id = client.callAsync(listener, "<method>");
}
In other methods I like to call this method (here "xmlRpcMethod") and wait until it finished. I wrote methods like this:
public void testMethod(){
Object sync = new Object();
xmlRpcMethod(sync);
synchronized (sync){
try{
sync.wait();
}catch(Interrupted Exception e){
e.printStackTrace();
}
}
// Do something after xmlRcpFinished
}
But this way of waiting and synchronizing get's ugly when the projects grows larger and I need to wait for many requests to finish.
So is this the only possible / best way? Or does someone knows a better solution?
My first shot to create blocking RPC calls would be:
// Little helper class:
class RPCResult<T>{
private final T result;
private final Exception ex;
private final long id;
public RPCResult( long id, T result, Exception ex ){
// TODO set fields
}
// TODO getters
public boolean hasError(){ return null != this.ex; }
}
public Object xmlRpcMethod() {
final BlockingQueue<RPCResult> pipe = new ArrayBlockingQueue<RPCResult>(1);
XMLRPCCallback listener = new XMLRPCCallback() {
public void onResponse(long id, final Object result) {
// Do something
pipe.put( new RPCResult<Object>(id, result, null) );
}
public void onError(long id, final XMLRPCException error) {
// Do something
pipe.put( new RPCResult<Object>(id, null, error) );
}
public void onServerError(long id, final XMLRPCServerException error) {
Log.e(TAG, error.getMessage());
pipe.put(new RPCResult<Object>(id, null, error));
}
};
XMLRPCClient client = new XMLRPCClient("<url>");
long id = client.callAsync(listener, "<method>");
RPCResult result = pipe.take(); // blocks until there is an element available
// TODO: catch and handle InterruptedException!
if( result.hasError() ) throw result.getError(); // Relay Exceptions - do not swallow them!
return result.getResult();
}
Client:
public void testMethod(){
Object result = xmlRpcMethod(); // blocks until result is available or throws exception
}
Next step would be to make a strongly typed version public T xmlRpcMethod().

How do you override Play framework controller in a unit testing context?

I am creating a basic POST JSON api endoint. I would like to unit test it, and want to make sure I am doing it appropriately in the Play framework. So far I am using Guice for dependency injection and JUnit for my unit testing library.
Here is my controller code:
public class NotificationController extends Controller {
private RabbitQueueService _rabbitQueueService;
#Inject
public NotificationController(RabbitQueueService service) {
_rabbitQueueService = service;
}
#BodyParser.Of(BodyParser.Json.class)
public Result post() {
ObjectMapper mapper = new ObjectMapper();
Notification notification;
try {
JsonNode notificationJsonNode = Controller.request().body().asJson();
notification = mapper.readValue(notificationJsonNode.toString(),
Notification.class);
_rabbitQueueService.push(notification);
return Results.created(notificationJsonNode, "UTF-8");
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return Results.badRequest();
}
}
My RabbitQueueService code:
public class RabbitQueueService {
private Channel _channel;
private Connection _connection;
public RabbitQueueService() {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(Config.RABBITMQ_HOST);
try {
_connection = factory.newConnection();
_channel = _connection.createChannel();
_channel.queueDeclare(Config.RABBITMQ_QUEUE, false, false, false, null);
_channel.exchangeDeclare(Config.RABBITMQ_EXCHANGE, "fanout");
_channel.queueBind(Config.RABBITMQ_QUEUE, Config.RABBITMQ_EXCHANGE, "");
} catch (IOException e) {
e.printStackTrace();
}
}
public void push(Notification notification) {
try {
_channel.basicPublish(Config.RABBITMQ_EXCHANGE, "", null, notification.getBytes());
_channel.close();
_connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void pop() {
}
}
My MockQueueService code:
public class MockQueueService extends RabbitQueueService {
#Override
public void push(Notification notification) {
/* Do nothing because you know... thats what I do */
}
#Override
public void pop() {
/* Do nothing because you know... thats what I do */
}
}
and finally my current unit test code:
public class ApplicationTest {
#Test
public void addMessageToQueue() {
running(fakeApplication(), new Runnable() {
public void run() {
FakeRequest request = new FakeRequest("/POST", "/api/v1/notifications");
Notification notification = new Notification(UUID.randomUUID(),
new NotificationType(UUID.randomUUID(),
"Critical"),
"Test notification message");
try {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(notification);
JsonNode node;
node = mapper.readTree(json);
request.withJsonBody(node);
} catch (IOException e) {
e.printStackTrace();
}
route(request);
}
});
}
}
This all works fine when making a curl request to test my endpoint through play run. My main question is: how do I use the MockQueueService in my unit test? I don't see anyway to do it with fakeApplication() helper. I could instantiate it directly like
NotificationController nc = new NotificationController(new MockQueueService());
nc.post();
but the problem is I need to override the body of the play request with an appropriate request body and I think I need a FakeRequest for that.
Any help, samples, or advice would be helpful.
UPDATE
I have posted a gist example with the necessary example files. The things specifically that I did to get it working:
Setup a new GlobalUnitTest file that I passed into the fakeApplication helper
Changed NotificationController to be a singleton. This allowed me to pull in the NotificationController instance so I could check the QueueService count as part of the assertion.
FakeApplication takes a bunch of arguments that you could use to inject your new service. You could use a combination of any of these:
additionalPlugins
additionalConfiguration
withGlobal
They each let you specify some additional configuration you could use only during testing. Another thing you could do is have a separate Global object just for testing, that is used to create your controllers. The Global object is used to return your controller instance when you use # in your route definition. Then, you can create a separate application.test.conf that refers to GlobalTest that is loaded when you run play test.

Categories