ADAL For Java on Mobile Devices: Prompt is Not Allowed - java

I've a Java program using ADAL4J that works great on a non-mobile device but when deployed to any mobile devices via Oracle MAF (which deploys as Cordova, HTML5, CSS), it fails on the AuthenticationContext method.
The error is:
com.microsoft.aad.adal.AuthenticationException: Prompt is not allowed and failed to get token:
Here is the main code:
service = Executors.newFixedThreadPool(1);
String url = AUTHORIZATION_ENDPOINT + tenantId + "/oauth2/authorize";
//Next line is where it fails
authContext = new AuthenticationContext(url, false, service);
Future<AuthenticationResult> future =
authContext.acquireToken(ARM_ENDPOINT, clientId, username, credential, null);
result = future.get();
System.out.println("Access Token - " + result.getAccessToken());
System.out.println("ID Token - " + result.getIdToken());
Based on the research I've done it appears I may need to use the AcquireTokenSilent method instead, however this method does not exist in the ADAL for Java library (using ADAL4J 1.1.3, most recent as of this post). I did see that there is an ADAL for Cordova library that contains this method that may work. However that uses NodeJS and I'd prefer to stick with a Java solution if possible.
Would appreciate any assistance. Thanks.
EDIT: I think the main issue if that the ADAL4J library does not support the AuthenticationContext.tokenCache property nor does it include support for the PromptBehavior option that is there in the device specific ADAL implementations.
If true, guess I'll either have to try the ADAL for Cordova or each device ADAL SDK.

According to your description, based on my understanding, I think you want to create a mobile application cross platform like iOS/Android/etc using Oracle MAF in Java.
So per my experience, the solution which be suitable for your needs in Java is using OAuth2 REST APIs for authentication via Java HTTP client on Azure AD, please refer to the offical tutorial OAuth 2.0 Authorization Code Flow.
If just for Android, you can directly use ADAL for Android to do that. Otherwise, it seems that there is not any existing library to directly support for authentication within multi-platform in Java. Hope it helps.

Related

How do I edit an Azure app registration from Java

I have a Java application that needs to update some fields of the manifest.json of an app registration in Azure.
I have already done this from the Linux terminal with the azure-cli tool. I then tried to google for a similar Java SDK to do this but only came up with SDKs that let you authenticate against Azure.
Is there another SDK for my use case or do I have to use some API directly via HTTP?
You can use Management SDK.
Sample code:
// skip this if you know the object id
ActiveDirectoryApplication app = azure.accessManagement().activeDirectoryApplications()
.getByName("<app_name>");
GraphRbacManagementClient client = azure.accessManagement().activeDirectoryApplications().manager().serviceClient();
client.getApplications().patch(
app.id(),
(ApplicationUpdateParameters) new ApplicationUpdateParameters()
.withGroupMembershipClaims(GroupMembershipClaimTypes.ALL));
It is a bit convoluted, because technically speaking AAD does not belong to Management. AAD is included in the SDK mainly for RBAC (role-based-access-control) for other resources.

How to pass the credential to Translation API v3?

I am using Google Cloud Translate v3 API Java Client. The Java Client code samples work great. The authentication of the code samples is done using the GOOGLE_APPLICATION_CREDENTIALS environment variable.
I need to develop code that will run in an application server that I have no control over the environment variables. So I need to use another way to get the call authenticated.
Setting Up Authentication for Server to Server Production Applications, under "Passing the path to the service account key in code" has a code sample (choose the JAVA tab) that works for the Storage service, but I can't find a similar way to pass the GoogleCredentials to Translation v3 API Java Client. Does anyone know?
Also, I can't find the Java doc for v3 API. https://googleapis.dev/java/google-cloud-clients/latest/index.html shows version "0.119.0-alpha" and it does not list the package com.google.cloud.translate.v3. Is there a separate java doc page ?
I think I found a solution.
The client API javadoc doesn't list com.google.cloud.translate.v3 but it does list com.google.cloud.translate.v3beta1. In the javadoc for TranslationServiceClient, i.e. https://googleapis.dev/java/google-cloud-clients/latest/com/google/cloud/translate/v3beta1/TranslationServiceClient.html
there's a mention of setting credential, and this method worked!
TranslationServiceSettings translationServiceSettings =
TranslationServiceSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(myCredentials))
.build();
TranslationServiceClient translationServiceClient =
TranslationServiceClient.create(translationServiceSettings);

Microsoft Azure Translation API authentication methods

I'm trying to set up Microsoft Translation API (part of MS Cognitive Services) in my Android app (using Java). I'm relatively new to Android programming and authentication methods, and I'm a bit confused with the those ones.
When I registered for an Azure account I created an Azure Directory, then created an Android App in the portal, configured it and got my auth_config.json .
Well, when I checked the MS translator API docs I saw that I can use it through a GET request and the API key provided. But also I saw I can authenticate by using a token, and that's where I'm stuck.
I've searching for days and I cannot find a clear and concise tutorial/guide/docs to Authenticate (no user context) from my Android app in order to use MS translate API by using tokens.
I found this link but it's only applicable when users have to sign in.
Any help related to auth tokens flow and conceptual design of them is also welcomed, but the main question would be "How to authenticate an Android App (no user context) by using tokens for accessing an Azure API?"
Thanks.
It sounds like you are trying to create a native Android Application using Java to get an access token in order to utilize the MS Translator API. But you would like to flow to be non-interactive.
You shouldn't need to get an access token in order to utilize the MS Translator API. Per the documentation you will only need to get the translator keys and then you will be able to use the Translator REST API using the Translator key.
The Translator Getting Started on how to setup and get keys can be found here :
https://learn.microsoft.com/en-us/azure/cognitive-services/translator/translator-text-how-to-signup
And the documentation on how to use the Translator API in Java can be found here :
https://learn.microsoft.com/en-ca/azure/cognitive-services/translator/quickstart-java-translate
In addition to that, I think it's important to understand the concepts of how to get access tokens from Microsoft for the future.
The v2.0(also referred to as converged) endpoint flows and explanation on how the authentication process works can be found here under "concepts > authentication > OAuth2 .... flow".
https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-scenarios
That being said, the MSAL library doesn't necessarily have all these flows implemented yet. To see more information on what MSAL libraries support what auth flows, you can find this information at the link here :
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-authentication-flows
Unfortunately we don't support the non-interactive flow using the MSAL Android library yet. If you're interested in this feature please submit an issue against the MSAL Android Library here : https://github.com/AzureAD/microsoft-authentication-library-for-android/issues
And one of the engineers that handles the library will reach out and discuss it further.
All the Azure AD libraries have wikis that can be found on their respective github repos. The MSAL Android one can be found here : https://github.com/AzureAD/microsoft-authentication-library-for-android/wiki
Hopefully this has been helpful, and if you have anymore questions please leave a comment.
Essentially you won't need to use MSAL and you should be able to just use the translator key to make calls to the MS Translator API.

AWS Cognito Sign-In with Java SDK for desktop application

I searched a lot, but it seems impossible to find a solution from start to finish to this topic. As a premise, I've already implemented Cognito sign-up, sign-in and refresh of credentials in two native apps for both iOS and Android, so I have developed a (at least) basic understanding of the authentication flow.
These mobile apps use the simplest cognito setup possible: a user pool, an identity pool with a IAM role for authenticated users and no unauthenticated usage possible. I'm not using (at least for now) Facebook, Google or Amazon login, nor other authentication methods.
Now I need to make a desktop version of those apps in Java, and it seems to me a completely different beast. What I would like to do is this:
Open the login window in my Java desktop application;
Insert username and password in their fields and press a login button;
Getting some credentials and start using the application connecting to other AWS services, specifically I need to use S3, Lambda and DynamoDB.
The way to achieve this is on paper reasonably simple:
Get a token from a Cognito user pool;
Give this token to a Cognito identity pool in exchange for some credentials;
Use this credentials to access other AWS services.
After reading a lot of documentation, downloading a lot of different projects examples and a lot of despair, I've eventually found the way to implement this in the mobile apps. For example, in Android the authentication flow works like this:
Instantiate a CognitoUserPool, using a UserPoolID, an AppClientID, a PoolRegion and (optionally) a ClientSecret;
Instantiate a credential provider, using an IdentityPoolID and a PoolRegion;
In the app UI, insert a username and password, and press the Login button;
Retrieve a CognitoUser using that username from the UserPool instantiated earlier;
Get a CognitoUserSession for that CognitoUser, using an AuthenticationHandler with various callbacks to pass the password when needed;
Add that CognitoUserSession to the credentials provider instantiated earlier, in form of a TokenKey + the JWT token extracted from the session.
At this point, whenever I need to access S3, Lambda or DynamoDB, I simply pass this credentials provider as a parameter for their clients constructors.
To implement the same functionality with the Java SDK seems to me much more difficult.
I managed to implement users Sign-Up fairly easily. However with users Sign-In I don't know where to start at all.
Every example does this in a different way. On top of that, every example uses particular use cases such as developer authenticated Sign-Ins, or custom urls to connect to some owned backend. Why is so difficult to find an example for a basic use case like the one I need? I'm starting to think my basic use case is not basic at all, but rather atypical. Why would login with a username and a password against the default users/credentials service for AWS be atypical, however, I don't really know.
The best I've done so far is copying the relevant classes from this example project (from which I've also taken the Sign-Up part, that works pretty well) and getting to print the IdToken, AccessToken and RefreshToken in the console. They are printed correctly and are not null.
What I cant't really understand is how to get the credentials and add them to a credentials provider in order to instantiate the clients to access other AWS services. The only way I see in the project to do that is to call the method
Credentials getCredentials(String accessCode)
which I suppose it should accept the access code retrieved with the InitAuth method (that starts an OAuth2.0 authentication flow, please correct me if I am wrong). The problem is that I can't find a way to retrieve that code. I can't find an online example of an access code to see how it looks. I tried to put one of the tokens and the web request responds
{"error":"invalid_grant"}
which suggests its not a valid code, but at least the web request is valid.
To make it more clear, what I can do is this:
String username; //retrieved from UI
String password; //retrieved from UI
//I copied AuthenticationHelper as is from the project
AuthenticationHelper helper = new AuthenticationHelper(POOL_ID, CLIENT_APP_ID, CLIENT_SECRET);
//I then retrieve the tokens with SRP authentication
AuthenticationResultType result = helper.performSRPAuthentication(username, password);
//Now I can successfully print the tokens, for example:
System.out.println(result.getAccessToken());
How can I retrieve the credentials from here? Where I should put the identity pool id? In Android I simply add the JWT token to an HashMap and use it like
credentialsProvider.setLogins(loginsMap).
Furthermore, this project contain classes with hundreds of lines of code, BigInteger variables, hardcoded strings of many lines of random characters (some sort of key or token I suppose) and other black magic like that (especially in the AuthenticationHelper class). Another thing I don't like about this solution is that it retrieves credentials through manually written web requests (with another separated class created ad hoc to make the request). Really isn't there in the Java SDK some handy method that wraps all those things in a bunch of elegant lines of code? Why call it an SDK than? The iOS and Android SDKs handle all that on their own in such a simpler way. Is this due to the fact that they expect a developer of desktop app to be way more able/expert, in contrast to the average guy that some day, getting up from bed, decides to make an iOS/Android app [alludes to himself]? This would explain their effort to make the mobile SDKs so developer-friendly in comparison.
Onestly I find really hard to believe that I have to do that, reading who knows what on a doc page who knows where, to Sign-In a user, which makes me think that I'm really missing something. I literally read every stack exchange question and documentation I was able to find. The fact is that there is almost always an AWS documentation page for what I need, but to actually find it is not so simple sometimes, at least for Cognito documentation.
I read that I can put a file with the needed credentials in the PC filesystem and the Java SDK will use those credentials to access all the resources, however from my understanding this method is reserved to Java applications running on a server as a backend (servlets), where the end user can't access them through his browser. My application is a desktop app for end-users, so I can't even consider to leave AWS credentials on the user PC (please correct me if I'm wrong, I would really love to make something so simple).
What really scares me is that Sign-In with a user pool and identity pool might not be possible at all. I know that Cognito related stuff was added to the Java SDK much later it was available for iOS, Android and JavaScript. But if they added it, I suppose It should support an authentication flow at least similar to those of the mobile counterparts.
What worsen the problem even more is that I initially made all the functionalities of my application to work offline. I thought that I would have eventually integrated AWS in the app. In this way the application is a bit more modular, and the AWS related stuff in concentrated in a package, detatched from the rest of the application logic and UI. In my sea of ignorance this seems a good practice to me, but now, if I cannot manage to resolve this problem, I've thrown months of work in the trash, only to realize that I have to build a web app beacuse JavaScript is much more supported.
Even on MobileHub the only options to create a ClientApp on Cognito is for iOS, Android, JavaScript and React-something.
When documentation or examples are provided for other languages/SDKs, Java is often omitted and the most frequent I see among the options is .NET.
To make my frustration even bigger, everytime I search something on a search engine, the fact that the word "Java" is contained in the word "JavaScript" obfuscates the few results that could be useful, because all the JavaScript SDK related stuff is generally higher ranked in the search engines than Java's (this could explain in part why .NET related stuff seems more easy to find, at least on StackOverflow or others Q&A sites).
To conclude, all of this created some questions in my head:
Why so few people seem to need this authentication method (with username and password)? It seems to me a pretty common and reasonable use case for a desktop application. I know that web apps growth is through the roof, but given that Java is one of the most used languages today, how is it possible that nobody needs to do a simple login from a desktop application? Which leads to the next question:
Is there something inherently bad/wrong/risky/stupid in using the Java SDK for a desktop application? Is it intended only for usage on a server as backend or for a web app? What should be the solution than, to make a desktop application that connects to AWS services? It is wrong to do an AWS connected desktop app at all? Should a web app the only option to consider? Why? I opted for Java to implement an application that would run on Widows, macOS and Linux. I also chose Java because i thought it would be mostly similar to the Android SDK in its usage, given its code should be indipendent from the platform UI, making simple to reuse code. I was wrong.
If there's nothing wrong in using the Java SDK like this, could some
good soul please help me find an example that goes from putting a
username and a password in two fields, and instantiate a client to
access other AWS services (such as an S3 client) in a Java desktop
application?
Tell me everything you need to know and I'll edit the question.
Please someone help me, I'm loosing my mind.
Probably too late for the OP but here is the process I used to get credentials from Cognito after obtaining the JWT identity token. Once the JWT is obtained through SRP Authentication I got the Identity Id using the Federated Pool Id and passing a login map of the Cognito Idp Url and the JWT. The url is completed with your aws region and your Cognito User Pool Id.
//create a Cognito provider with anonymous creds
AnonymousAWSCredentials awsCreds = new AnonymousAWSCredentials();
AmazonCognitoIdentity provider = AmazonCognitoIdentityClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withRegion(REGION)
.build();
//get the identity id using the login map
String idpUrl = String.format("cognito-idp.%s.amazonaws.com/%s", REGION, cognitoUserPoolId);
GetIdRequest idrequest = new GetIdRequest();
idrequest.setIdentityPoolId(FED_POOL_ID);
idrequest.addLoginsEntry(idpUrl, jwt);
//use the provider to make the id request
GetIdResult idResult = provider.getId(idrequest);
return idResult.getIdentityId();
If you're using a different login provider then that url needs to change, but this should get the Identity Id. Next its a similar request to get the IAM credentials by passing the Identity Id and that same login map.
//create a Cognito provider with anonymous creds
AnonymousAWSCredentials awsCreds = new AnonymousAWSCredentials();
AmazonCognitoIdentity provider = AmazonCognitoIdentityClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withRegion(REGION)
.build();
//request authenticated credentials using the identity id and login map for authentication
String idpUrl = String.format("cognito-idp.%s.amazonaws.com/%s", REGION, cognitoUserPoolId);
GetCredentialsForIdentityRequest request = new GetCredentialsForIdentityRequest();
request.setIdentityId(identityId);
request.addLoginsEntry(idpUrl, jwt);
//use Cognito provider to perform credentials request
GetCredentialsForIdentityResult result = provider.getCredentialsForIdentity(request);
return result.getCredentials();
This took me a full week to figure out. AWS Java documentation is pretty terrible in my opinion. Hopefully this helps someone out.

Allowing only my android apps to execute endpoint api in java

I created endpoint apis but problem is anyone with my project id can go to api explorer and execute those apis. I have put only android client id (using debug keystore) on top of endpoint class declaration but still I can go to incognito mode and execute the apis. How can I restrict the apis so that only my android apps have access and all others will be thrown with some exception?
The APIs can be protected by adding a key parameter that has to be correct for API to be invoked. If the user of the API does not know the key, he won't be able to use the API even with API Explorer.
Advantages of this approach is that it is simple to do, allow you yourself to experiment with the API if you need.
Disadvantages include being very easy to circumvent by a determined user, just by looking at the traffic.
You need to make sure that you have coded your API/backend correctly to only accept the clientId for your app; make sure that you do not see com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID as one of the clientIds in your #Api annotation on the API class:
#Api(
name = "myApi",
version = "v1",
clientIds = {<your android clientId>},
)
public class myApi {
// your API code here
}
If the API Explorer client ID is present, it will allow it to execute your API from the API. I am not 100% sure, but I think you may still see your API form the explorer without the client ID, but execution will be prevented with an error.
This article has more info: https://cloud.google.com/appengine/docs/java/endpoints/auth#Specifying_authorized_clients_in_the_API_backend
You may want to think about putting proper auth around the endpoint calls (i.e. per-user auth checks around each method) if it is particularly sensitive. Just adding a User parameter to the #ApiMethod should be enough for force users to auth before executing each method.
Hope that helps.
You can use on each api allowed_client_ids to be ANDROID_CLIENT_ID only, can be a possible workaround.
I think this could help if you haven't followed it yet : https://cloud.google.com/appengine/docs/python/endpoints/auth#Python_Creating_OAuth_20_client_IDs
Use symmetric key cryptography along with digital signatures for this. However, you'll need to share the key with the Android app first.
Here's how it would work.
Whenever the Android app is making a network request, you take the URL & the parameters, then you Hash it and then encrypt it using the shared private key. You then append the signature as another parameter to the URL.
At the receiving end, your web API will validate whether the request came from your Android app ONLY.
Please note, that this will work ONLY for your app. It will not work as a way to catch all generic Android requests/
Here are some points for consideration :
Cloud Endpoints has been supporting the ANDROID CLIENT ID and
package signing, so that should atleast take care of the fact that
only a signed Android application from your side can access the
endpoint
.
If you wish to remove the Web Clients from access, then I would
probably look into the HTTP Headers and Agents to see if there is a
sure way of identifying these web clients.However, this would
require that you write your own Authorization logic in the method
since I do not believe that the endpoints infrastructure can take
care of this automatically for you
.
Remove access for everyone via the Annotations could be
problematic if you want a quick way to use the API Explorer to test
out the API. So do keep the API Explorer access available.

Categories

Resources