Fusion Tables and Service Accounts - android

I'm trying to get my app to upload to Fusion Tables without the need to grant every user write permissions to the table beforehand. This is because of security reasons and just to make the system simpler.
Currently, to create an instance of com.google.api.services.fusiontables.Fusiontables, I do:
private static Fusiontables constructFusionTables(Context context) {
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(context,
Arrays.asList("https://www.googleapis.com/auth/fusiontables"));
String username = "someuser#gmail.com";
credential.setSelectedAccountName(username);
return fusiontables = new Fusiontables.Builder(HTTP_TRANSPORT,
JSON_FACTORY, credential).setApplicationName("someappname")
.build();
}
When I try to use a service account email ( XXXXXXX#developer.gserviceaccount.com ), all the Fusion Tables queries made with that FusionTables instance fail telling me that name must not be null.
As a quick workaround for testing, I tried to hardcode a username ( someuser#gmail.com ) that is not on the device's Google Account list, but it gives me the same error.
The error doesn't appear when I use normal user#gmail.com accounts that exist on the phone.
Could you guide me on how to implement a Service Account to Fusion Tables in Android?

Related

Signing up a new Firebase account using a currently logged acount(Android)

I'm working on an educational app wherein teachers can create/edit/delete topics and activities for the students while monitoring their progress(like SoloLearn), i'm at 90% progress now and was testing the app when I encountered this problem. I create the app so that only the teacher accounts can create accounts for the students. As I login the teacher account it will show the basic info of the teacher(name, email, advisory class), seems good, but when I created an account for a student(teacher account currentUser), my app replaces the currentUser with the student account that I just created(Tested).
So my question is how can I resolve the issue where in creating a new account within an account replaces the current user?
Basic info of the teachers/students are saved in FirebaseDatabase using email as a key.
I'm using the Firebase Assistant in creating the account.
my Code in retrieving userEmail and DatabaseReference
String currentEmail = mAuth.getCurrentUser().getEmail();
mDataRef = FirebaseDatabase.getInstance().getReference()
.child("AccountInfo").child("Teacher").child(EncodeString(currentEmail));
EncodeString is just a String replace for "." to "DOT".
I think a better and more secure way of doing this is to use the Firebase Admin SDK.
You would set a custom user claim on teachers to differentiate them from students. Then on student creation, send the teacher's ID token and the student's info to a server where you confirm teacher role and then create the user with Admin SDK.
Otherwise, if you just want to create another account without logging out the teacher, you can explicitly [instantiate a new FirebaseApp instance](https://firebase.google.com/docs/reference/android/com/google/firebase/FirebaseApp.html#initializeApp(android.content.Context, com.google.firebase.FirebaseOptions, java.lang.String)) and use the other non-default instance to create the accounts.
However, from a security point of view, the first suggestion is the right way to do it.

Service account client Id : com.google.android.gms.auth.GoogleAuthException: Unknown

I'm trying to create a simple Andriod App which allows users to login using Google+ Sign in.
Once signed in, they can access a J2ee server urls. As part of J2ee server logic, i want to validate whether the requests are coming from authenticated and\
riod app.
Based on google help documentation and lot of other blogs, i have created 2 clientds ( under Credentails section in google developer console ).
Client ID for Android application
Service account
private static final String scopes = "audience:server:client_id:" + SERVER_CLIENT_ID; // id from Service Account
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
Account account = new Account(accountName, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
String idToken = GoogleAuthUtil.getToken(getApplicationContext(), account, scopes);
I am getting error at the last line ( GoogleAuthUtil.getToken ).
com.google.android.gms.auth.GoogleAuthException: Unknown
I am not able to proceed further. Am i doing something wrong here??
I see a lot of similar questions on stackoverflow, however most of them seem to their issues fixed. I tried every suggestion. Looks like i am doing somethi\
ng wrong.
Can someone point me in the correct direction.

User data in account manager is accessible by other applications

I am trying to utilize Android's Account Manager to store user's app credentials.
Although I am not saving the user's password, I wanted to save other security keys to the account's UserData. According to the documentation quoted below, this should NOT be accessible by applications with different UID.
public String getUserData (Account account, String key)
Gets the user data named by "key" associated with the account. This is intended for authenticators and related code to store arbitrary metadata along with accounts. The meaning of the keys and values is up to the authenticator for the account.
It is safe to call this method from the main thread.
This method requires the caller to hold the permission AUTHENTICATE_ACCOUNTS and to have the same UID as the account's authenticator.
Parameters
account - The account to query for user data
Returns
The user data, null if the account or key doesn't exist
To test this, I created an application that creates an account and saves some contents to UserData. I also created another application that accesses the accounts of the first app. Below are the snippets:
First app:
AccountManager am = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
final Account account = new Account("Account Name", "my.account.type");
am.addAccountExplicitly(account, null, null);
am.setAuthToken(account, "my.account.type", "some auth token");
am.setUserData(account, "key.for.secure.user.data", "some secure data");
Second app:
AccountManager am = (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE);
Account[] accountsFromFirstApp = am.getAccountsByType("my.account.type");
for(Account acct: accountsFromFirstApp){
printToLogs(acct.name);
printToLogs(am.getUserData(acct, "key.for.secure.user.data"));
}
Based on the documentation above, I expected the second app's getUserData() to return an exception for not having the same UID as the owner app. Surprisingly, I was able to access the user data of the first app with no errors.
But when I tried to access accounts from google by using "com.google" as the accountType, I got the expected exception.
What was wrong with my implementation? Did I miss some configuration that was not stated in Android's documentation? Any help will be very much appreciated.
On the second thought, If these user data can just be accessed that easily (assuming that the other applications know my app's account type), then what's the difference of storing strings in UserData from storing them in SharedPreferences instead?
From the AccountManager documentation:
This class provides access to a centralized registry of the user's online accounts. The user enters credentials (username and password) once per account, granting applications access to online resources with "one-click" approval.
Accounts managed by the AccountManager are centralized and reusable, e.g. all Google apps can use the same account, and not every app has to create its own Google account.
So one of the ideas of the AccountManager, as far as i understand, is to have reusable accounts, accessible from different apps.
But as the stored credentials are accessible from different places, you shouldn't store any plain text passwords in the AccountManager.
May this topic is interesting for you: What should I use AccountManager for?
If your data is Personal data, you can encrypt it, so no other apps can read them.
I.E using AES Encryption like this:
public class AESCryptor
{
private static final String ALGORITHM = "AES";
// 16-bit Key for encryption (Change to yours)
private static final String KEY = "XXXXXXXXXXXXXXX";
public static String encrypt(String value) throws Exception
{
Key key = generateKey();
#SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance(AESCryptor.ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte [] encryptedByteValue = cipher.doFinal(value.getBytes("utf-8"));
return Base64.encodeToString(encryptedByteValue, Base64.DEFAULT);
}
public static String decrypt(String value) throws Exception
{
Key key = generateKey();
#SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance(AESCryptor.ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedValue64 = Base64.decode(value, Base64.DEFAULT);
byte [] decryptedByteValue = cipher.doFinal(decryptedValue64);
return new String(decryptedByteValue,"utf-8");
}
private static Key generateKey() {
return new SecretKeySpec(AESCryptor.KEY.getBytes(),AESCryptor.ALGORITHM);
}
}
I use it in my apps, and it works!
This maybe doesn't answer the question
User data in account manager is accessible by other applications
But its answered by #thomas-s-e
Regards,
#developerfromjokela

Authenticate my "app" to Google Cloud Endpoints not a "user"

What I'm trying to do is to authenticate my Android app to the Google Cloud Endpoint.
Basically the endpoints should only allow my Android app to access the methods and nothing else.
I have done these things -
Create a client id using my SHA1 value in Eclipse in the Google Cloud Console.
Create a web client id in the Google Cloud Console for my endpoint project.
Add both these client id's in the "#Api" mentioned on each endpoint.
Add an extra "user" parameter in the endpoint methods.
Regenerate and deploy the backend to the cloud.
But when I'm running this the "user" is always coming as "null". I'm at my wits end trying to find a proper working method for doing all this.
I've searched many forums but no proper answers anywhere.
Here's another similar post Restrict access to google cloud endpoints to Android app
This is the reference I'm using -
https://developers.google.com/appengine/docs/java/endpoints/auth
Has anyone here done this before? My main goal is to not allow unauthenticated apps and outside world to access the endpoints, for obvious security reasons. I don't want to use end-user based authentication since I want to keep my app very simple.
It sounds like it's working as intended. You control which client apps can call your endpoint methods via the client IDs as you have already done. The User parameter is coming in as null precisely because you aren't doing end-user authentication. The User parameter represents an actual real user (Google Account). So if you don't need end-user authenticated methods, you can just simply not define the User parameter, or else ignore the null value. You said your problem is that the User parameter is set null. What are you expecting it to be in this scenario?
You need to call authenticate on the client, then possibly the library you're using will 'inject' the user information.
Here's what worked for me :
Let's say you have the keys below :
static final String WEB_CLIENT_ID = "somekeyfor webclientid.apps.googleusercontent.com";
static final String ANDROID_CLIENT_ID = "somekeyfor androidclientid.apps.googleusercontent.com";
static final String ANDROID_AUDIENCE = WEB_CLIENT_ID;
Your Api anotation should look like this :
#Api(
name = "yourapiname",
clientIds = {CloudEndpoint.WEB_CLIENT_ID,CloudEndpoint.ANDROID_CLIENT_ID},
audiences = {CloudEndpoint.ANDROID_AUDIENCE},
version = "v1",
namespace = #ApiNamespace(
ownerDomain = "myapp.app.com",
ownerName = "myapp.app.com",
packagePath = ""
)
)
In the annotation below, notice how your audience is the variable --> ANDROID_AUDIENCE which is equal to WEB_CLIENT_ID.
Now in your app side, when you create the googleAccountCredential object, you should pass in the Web Client Id like this :
mAccountCredentials = GoogleAccountCredential.usingAudience(getApplicationContext(),"server:client_id:" + "yourwebclientID");
Note that even if this is properly done, your user object in the endpoint might still coming out as Null if the account name you pass in mAccountCredentials.setSelectedAccountName("accontname") does not exist in the device. Therefore make sure the account name you pass does exist in the Android device by going to --> (Settings/Accounts)

getting account name in appengine connected android project

I have an android application connected to an appengine backend through endpoints. I would like the application to know the user's google account name and I wondered if there was an easy way, without going through all the authentication procedure described here
I don't really care about the security stuff at the moment, I would just like, for example, to be able to say "hello" to the user by using his name, or to store in the datastore a list of usernames that used the application. And I don't want users to be forced to enter a password to use my app.
I tried to use the code
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this, "appname.appengine.com");
String try= credential.getSelectedAccountName();
inside OnCreate() but it gives an null result. I also tried to put
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
inside the endpoint, but it doesn't work either.
Any help? Thanks in advance!
You can use the account manager to get the users' account w/o actually authenticating the accounts, e.g.:
// Requires android.permission.GET_ACCOUNTS
AccountManager manager = AccountManager.get(ctx);
Account[] accounts = null;
try {
accounts = manager.getAccounts();
} catch (SecurityException e) {
Log.i(CTAG, "Unable to read due to SE");
}
if (null != accounts)
for (Account account : accounts)
Log.v(CTAG, "New account =" + account.name + ", " + account.type );
This should satisfy your requirement to store a list of the users who used your app.
However, this does not give you the actual name of the user for greeting them. To get the users' name you need to use the profile API that was added with ICS (and which requires READ_PROFILE permission). You can get their name here:
http://developer.android.com/reference/android/provider/ContactsContract.CommonDataKinds.StructuredName.html

Categories

Resources