Implementing Azure Communication Services - Chat in Android application - android

I'm trying to implement Chat functionality in the Android app using Azure Communication Services (Chat). I used https://learn.microsoft.com/en-us/azure/communication-services/quickstarts/chat/get-started?pivots=programming-language-android this link to set up the Android project. Inside the Android app, we need few configuration data of Azure communication resources like,
String endpoint = "https://<resource>.communication.azure.com";
String firstUserId = "<first_user_id>";
String secondUserId = "<second_user_id>";
String firstUserAccessToken = "<first_user_access_token>";
After going through Microsoft doc, I found this link Access Token Generation, a console application for creating Identity.ID and Access Token. And I used the same access token and Identity.ID which was generated by console application for FirstUserAccessToken and First UserID. Once this is done I ran the Android app, but I got a Null pointer exception while calling
CreateChatThreadResult createChatThreadResult = chatAsyncClient.createChatThread(createChatThreadOptions).get();
On calling .get app throws a exception.
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.azure.android.core.http.HttpResponse.getStatusCode()' on a null object reference
First place, want to know whether the AccessToken and UserId that I'm using are correct or not.
Am I missing something here? Or is there any server-side setup to be done for the same?

First place, want to know whether the AccessToken and UserId that I'm using are correct or not.
Yes, using the CommunicationIdentityClient to create a user and issue a token is the right approach. Just make sure you specify the right scope. This example requires setting the CHAT scope.
List<CommunicationTokenScope> scopes = Arrays.asList(CommunicationTokenScope.CHAT);
CommunicationUserIdentifierAndToken result = communicationIdentityClient.createUserAndToken(scopes);
Recently, there's been a new option added to quickly generate Azure Communication Services access tokens for testing - you can do it directly in the Azure Portal.
I just quickly tried the finalized sample code from GitHub and it worked flawlessly. The steps I took:
installed Android Studio + Android 11 SDK (API level 30)
created a Pixel 4 device running Android 11
cloned the repo
replaced the endpoint, firstUserId, secondUserId, firstUserAccessToken with values generated in the Azure Portal
ran the sample + successfully debugged it

Related

Unable to get ID token (Azure AD) using MSAL 1.0 for Android

In our Android app that uses MSAL 1.0 we can successfully sign-in to Azure AD. However, we cannot find a way to get ID token. Some examples on line show two ways to get ID token: IAuthenticationResult.getIdToken() and IAccount.getClaims().get("id_token"). Neither of the methods works for us. The former does not exist as a method in IAuthenticationResult. The latter always returns null.
I've looked at the source code that does the signing in and noticed that ID tokens are acquired and parsed into claims. However, it does not look like they are made available to library users in their raw formats.
I've verified during debugging that valid ID tokens are being acquired.
Our app needs to pass ID tokens to our back-end server.
Is there another way to access ID tokens using MSAL?
Btw, we do not have this problem on iOS and MSAL.
I have confirmed that the feature is not present in the Android version (although the id token is accessible as a string in the iOS version). It will be implemented in the future. For reference look here:
https://github.com/AzureAD/microsoft-authentication-library-for-android/issues/850

Unable to create a Thing in AWS IoT using AWS sdk for Android

How to create a Thing in AWS IoT using AWS sdk for android? Every time I try to execute my code it fails with a Network exception error. My target is to create a Thing with a Thing Name which will be visible in the AWS IoT dashboard. Below is what I tried.
CreateThingRequest thingRequest = new CreateThingRequest();
thingRequest.withThingName("NewTestThing");
CreateThingResult thingResult = mIoTAndroidClient.createThing(thingRequest);
Providing android logs will be helpful. Also, do check that you are not running the snippet of code in the main thread.

Microsoft Azure Translator Android API not working

I was trying to make a text translator app using Microsoft-translator-API but I am not able to receive any response from this API, I always get this message:
[microsoft-translator-api] Error retrieving translation: Unable to resolve host "datamarket.accesscontrol.windows.net": No address associated with hostname
even I have given correct client Id and client secret Id.
I tried this link but I don't know where to put the JSON-Simple.jar file. I tried this link too but still with no success. I am pasting my code below:
public String translateText() throws Exception {
Translate.setClientId("whateveritis");
Translate.setClientSecret("whateveritis");
translatedText = Translate.execute(
userText.getText().toString(),
languages[sEnterLan.getSelectedItemPosition()],
languages[sTransLan.getSelectedItemPosition()]);
Language detectedLanguage = Detect.execute(userText.getText()
.toString());
this.detectedLanguage = detectedLanguage.getName(Language.ENGLISH);
return translatedText;
}
By calling above function I can receive the translated text into a string variable but every time I get an exception.
According to your code and reference links, I think you were using the third party Java wrapper boatmeme/microsoft-translator-java-api for MS Azure Translator API. However, it's an old Java wrapper which wrappered the old & unavailable APIs from the old site Azure datamarket. There is a notice at this site, and all origin APIs had been migrated to Azure subscription.
DataMarket and Data Services are being retired and will stop accepting new orders after 12/31/2016. Existing subscriptions will be retired and cancelled starting 3/31/2017. Please reach out to your service provider for options if you want to continue service.
So I suggested that you can try to refer to my answer for the other SO thread Microsoft Translator API Java, How to get client new ID with Azure to create a cognitive service for Translator Text API on Azure portal and use it via the new REST APIs.
Hope it helps.

Google Cloud Datastore / Mobile Backend Starter - Permissions failure on update/updateAll calls

Using the Mobile Backend Starter (MBS) Android classes (those distributed as a sample project when creating a new project in Google Dev Console and demoed at Google I/O 2013) I'm able to insert new entities to the cloud datastore via calls to CloudBackendMessaging.insertAll or .updateAll. The latter will create entities if none exist so seems functionally identical to insert for new records.
The insertion/creation works fine. However when I attempt to update existing entries in the datastore, I received permissions errors e.g. (from the backend log)
Method: mobilebackend.endpointV1.updateAll
Error Code: 401
Reason: required
Message: Insuffient permission for updating a CloudEntity: XXXXXX by: USER: YYYYYYY
which results in a matching access error in the logcat client side.
In all cases I am using Secured access authenticating with a valid Google account (my own).
The entities being inserted are thus showing as "owned" by my user ID with "updated by" and "created by" showing my Google account's email address.
However when the update of the existing record is made, using exactly the same CloudBackendMessenger object and thus same credentials etc. the backend is telling me I can't update due to permissions issues. But surely if I just made the entity with the same credentials this can't be correct? Looking at the documentation it appears that I should be able to edit entities owned by the same user ID in all cases (regardless of the KindName and whether it is prepended [public], [private] or nothing).
Can anyone who has received permissions errors on UPDATES via Mobile Backend Starter for Datascore please shed any light? I have been banging my head over this for most of today.
I've faced the similar error "Insuffient permission for updating a CloudEntity" when using cloudBackendAsync.update(cloudEntity). I resolved it by making sure the cloudEntity has it's createdAt field set. createdAt is autogenerated and I think I am not supposed to touch it. But it worked for me. In my case I am first obtaining list of cloud entities. This is when I get createdAt field of cloud entities. Then when I am updating I setting the createdAt field from previously obtained entities.
Edit: Had to do similar thing for owner field also.
Similar to one of the comments above, I successfully got around this by getting the original CloudEntity before doing the insert/update/delete function.
CloudQuery cq = new CloudQuery("datastoretype");
cq.setLimit(1);
cq.setFilter(Filter.eq("_id",id));
cloudEntity.setId(id);
mProcessingFragment.getCloudBackend().get(cloudEntity, handler);
Thereafter it was trivial to do the following:
mProcessingFragment.getCloudBackend().update(cloudEntity, handler);
The docs definitely ought to be more clear on this, whether it is a strict requirement or bug.
The answers posted so far work around the problem if you don't mind all users being able to access the entity you are trying to update. However, a better solution that retains the access permissions is detailed by google here - https://cloud.google.com/cloud/samples/mbs/authentication
If you want to pass the user’s Google Account info to the backend on
each call, use the CloudBackend#setCredential() method (also available
on the subclasses, CloudBackendAsync and CloudBackendMessaging) to set
a GoogleAccountCredential object before calling any Mobile Backend
methods.
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this, "<Web Client ID>");
credential.setSelectedAccountName("<Google Account Name>");
cloudBackend.setCredential(credential);
Setting credientials enables the client to operate when the backend is
in “Secured by Client ID” mode and also sets createdBy/updatedBy/owner
properties of CloudEntity automatically.

How do I restrict Google App Engine Endpoints API access to only my Android applications?

I am an Android developer building my first Google App Engine (java) back-end for my apps. I don't want anybody else to access this API other than my app. (I plan to use App engine for verifying InApp purchases in my Android app). My data is not relevant to users so,
I don't want users to be able to access my API even if they are logged in with their Google accounts (on web or Android devices).
I followed the steps mentioned in - "Specifying authorized clients in the API backend"
(https://developers.google.com/appengine/docs/java/endpoints/auth)
like generating client IDs and add them in #Api (clientIds and audiences)
except "Add a User parameter" - since I don't need user authentication.
Then I deployed App engine and I am still able to access the API through API explorer (https://your_app_id.appspot.com/_ah/api/explorer)
(I haven't added API_EXPLORER client ID)
I tested with the APK that was built with the endpoint libs before adding client IDs and can still access the API.
Is adding a "User parameter" to all endpoint APIs a must? to achieve my purpose (restrict API to only my Android apps).
Can I pass null as userAccount name from Android client and ignore user parameter value on server (since it will be null)? Will this ensure that the API is accessible only from my android apps (since the client ID is generated for my package name and SHA1 of the APK?)
Should I use something like a service account for this purpose?
The documentation says for Android, both Android and Web client IDs must be added and audience must be the same as web client ID. Does this open access to any other web client? can I skip mentioning web client ID and still achieve my purpose?
Appreciate your time and help.
...... updating with my further investigation ...
I did the following:
Added User parameter to APIs on backend - but did not check for null value. API can still be accessed without passing any credentials (from Android debug APK and API explorer)
Then, I tried
mCredential = GoogleAccountCredential.usingAudience(this, "server:client_id:" + WEB_CLIENT_ID);
mCredential.setSelectedAccountName(null);
and passed this credential to API builder (as suggested in some other posts)
Caused FATAL EXCEPTION. So, we can't pass null account name.
I could call the API using API explorer without OAuth. But when I enabled OAuth, it gave error saying this client ID is not allowed! ( I haven't yet added com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID in client_ids{})
Then I added code to throw OAuthRequestException on the backend if the user is null. This resulted in API explorer getting errors without OAuth. It works with OAuth enabled after adding API_EXPLORER_CLIENT_ID to client_ids)
Added code to pass valid user account name(email) from my Android app. Then, I am able to access API only with my release APK. Even the debug APK gets exceptions! - which is what I expected..So, I assume no other Android apps will be able to access this API.
So, not checking for null user on back-end API is a bad idea (as suggested in other posts). It is as good as not mentioning any client_ids and not having User param.
Only question I have at this moment is: If some one can figure out the WEB_CLIENT_ID from the APK, will they be able to use it to build a web client to access my API (I haven't mentioned client secret anywhere in the code. So I am thinking this is not possible).
I did search Google groups and Stackoverflow, but still it is not clear.
(Authenticate my “app” to Google cloud endpoints not a “user”)
Authenticate my "app" to Google Cloud Endpoints not a "user"
(How do I protect my API that was built using Google Cloud Endpoints?)
How do I protect my API that was built using Google Cloud Endpoints?
(Restrict access to google cloud endpoints to Android app)
Restrict access to google cloud endpoints to Android app
I had a similar issue, not between Android and App Engine, but between a separate server and App Engine. The way I handled it was to add a signature hash field as a parameter to each API call. If the request had an improper signature, it would be denied.
For example, suppose your API end-point is example.com/api/do_thing?param1=foo. I would hash the entire url, along with a secret key, and then append the result of the hash to the request: example.com/api/do_thing?param1=foo&hash=[some long hex value].
Then, on the server side, I would first remove the hash from the url request, then run the hash on everything that was remaining. Finally, you check whether the calculated hash matches the one that was sent with the request and if they don't, you can deny the request.
It is very important however that your secret key remain secret. You have to be careful with this on Android because someone could attempt to decompile your APK.
Facing the same problem than you ! Authenticate Android End point without Google User Account is just impossible !
So here is my way to resolv this problem, without any user interaction (Maybe not the right but that works, and you've got strong authentication (SHA1 + Google Account)):
HERE IS MY ANDROID CODE
Get and Build Valid Credential
//Get all accounts from my Android Phone
String validGoogleAccount = null;
Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
Account[] accounts = AccountManager.get(context).getAccounts();
for (Account account : accounts) {
if (emailPattern.matcher(account.name).matches()) {
//Just store mail if countain gmail.com
if (account.name.toString().contains("gmail.com")&&account.type.toString().contains("com.google")){
validGoogleAccount=account.name.toString();
}
}
}
//Build Credential with valid google account
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this,"server:client_id:301991144702-5qkqclsogd0b4fnkhrja7hppshrvp4kh.apps.googleusercontent.com");
credential.setSelectedAccountName(validGoogleAccount);
Use this credential for secure calls
Campagneendpoint.Builder endpointBuilder = new Campagneendpoint.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), credential);
HERE IS MY API BACKEND CODE:
API Annotation
#Api(
scopes=CONSTANTES.EMAIL_SCOPE,
clientIds = {CONSTANTES.ANDROID_CLIENT_ID,
CONSTANTES.WEB_CLIENT_ID,
com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
audiences = {CONSTANTES.ANDROID_AUDIENCE},
name = "campagneendpoint",
version = "v1"
)
Method code:
public Collection<Campagne> getCampagnes(#Named("NumPortable")String NumPortable, User user) throws UnauthorizedException {
if (user == null) throw new UnauthorizedException("User is Not Valid");
return CampagneCRUD.getInstance().findCampagne(NumPortable);
}
For the moment, it only works on Android (I don't know how we gonna do on IOS..)..
Hope It will help you !
Google provides ways to do this for Android, web and iOS
The steps involves:
Specifying a client Id for apps you want to allow to make requests to your API
Adding a User parameter to all exposed methods to be protected by authorization.
Generating the client library again for any Android clients
Redeploying your backend API.
Updating the regenerated jar file to your Android project for your Android client.
These steps are laid out in clear detail on Google's Using Auth with Endpoints and also on this blog
Facing the same problem, here are the result of my research :
Added Android cliend id with SHA1 fingerprint in Google console
Use of it in the API annotation
BUT :
If i dont add user parameter to methods : the check about android app client id does not work
If I add the USER parameter but do not ask the user to choose its google account to create the credential ... also it does not work ...
Conclusion : It seems to be mandatory to connect a user account for the check about the app client id to be executed ... I really do not understand why because no link exist between the 2 processes
Access this site
Choose your project, go to credentials section
Create a new api key
Create a new android key
Click on "Edit allowed android applications" and enter your SHA1 key; your android package name
Let me know if this solves the issues.

Categories

Resources