AWS MQTT Websocket, authenticated access being restricted - java

I'm currently working on an AWS mobile app project in Android Studio, and I'm currently trying to set up a MQTT-connection to AWS IoT through AWS Cognito & IAM authentication.
If I run the MQTT-client as a stand-alone project without authentication, assuming an unauthenticated IAM role, I'm able to connect to MQTT, and subscribe & recieve from the given topic.
However, once I try to run my MQTT-client through an authenticated user (through a log-in on my mobile app), the client is restricted, and constantly tries to reconnect.
I enabled logging in AWS CloudWatch, and the following debug message is given:
"... EVENT:MQTT Client Connect MESSAGE:Connect Status: AUTHORIZATION_ERROR"
The unauth and auth roles in the IAM console have identical policies & resource access, yet something's stopping the MQTT connection.
PS. The Auth role can, in my app, access userfiles & S3, the probelem seems to be unique for IoT access.
Does anyone know if it's possible to allow connections through an authorized user without using cert-files, if so, how? Unless I'm mistaken Cognito and IAM should be able to perform the required authorization to access resources (and it does, as long as I'm not logged in to the auth role)
Appreciate any tips I can get at this point, been struggling for a while.

I eventually figured out the issue by reading the AWS documentation more thoroughly.
The AWS credentials provider does not store the required information to authorize access through AWS. So I solved the issue by retreiving the required user tokens into a hash, and setting these to the credentials provider, and the issue was finally solved.
AuthenticationResultType authenticationResultType = new AuthenticationResultType();
String idToken = authenticationResultType.getIdToken();
// Initialize the AWS Cognito credentials provider
credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
COGNITO_POOL_ID,
MY_REGION
);
Map<String, String> logins = new HashMap<String, String>();
logins.put("yourAWSEndpoint", idToken);
credentialsProvider.setLogins(logins);

Related

Microsoft Graph Api - getting access without a user in java

I have a problem auth with microsoft graph api. I never work with it.
I try to write application responsible for downloading attachments from mails.
The program will be scheduled from platform so it cannot get admin consent (therefore authorize using Client Credentials).
Every code example I found required an user interaction to sig in on microsoft to get a token.
I received from admin in my company below items:
clientID, tenantID, app name, mailbox address
and permission EWS.AccessAsUser.All (should I request about Mail.Read permission? mailbox can be easily migrate to 0365. If I well understand EWS is for exchange)
I'd like to connect to mailbox and download attachments.
Is any way to receive authentication with clientID, tenantID ? any provider exist ? without user interaction to get a token?
You can obtain an app-only token by using Microsoft Graph Java SDK.
ClientCredentialProvider authProvider = new ClientCredentialProvider(
this.clientId,
this.scopes,
this.clientSecret,
this.tenantId,
this.endpoint);
IGraphServiceClient graphClient = GraphServiceClient
.builder()
.authenticationProvider(authProvider)
.buildClient();
You can find a full example in the java spring webhook sample. There's however a small caveat because of the authentication SDK as described here.
The permission you need to request is Mail.Read of type Application Permission under Microsoft Graph in the application registration portal. Once you've added that permission, do not forget to click the Grant admin consent for XXX button on top of the permission list (this is how you grant permissions if you don't have a UI flow).
Lastly, EWS is a separate API from Microsoft Graph, you shouldn't need any permission for it in your case.
you can get Access token using below code reference from Microsoft which uses Java SDK.
https://github.com/Azure-Samples/ms-identity-java-daemon/blob/master/msal-client-credential-secret/src/main/java/ClientCredentialGrant.java

Firebase authentication untrusted java client with valid Firebase token

I'm building a small Java client with a Angular frontend to be distributed to clients.
At the moment I have a login screen via Angular which returns a valid firebase token. Where I'm unsure is how can I use that token to authenticate the user against the Java part of the application, so the Java client can perform actions such as file uploads.
With the Admin SDK I can do something like:
public FirebaseAuth firebaseAuth() throws IOException {
FileInputStream serviceAccount = new FileInputStream(new ClassPathResource(SERVICE_ACCOUNT_KEY).getFile());
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl(String.format("https://%s.firebaseio.com/", DATABASE_NAME))
.build();
FirebaseApp.initializeApp(options);
return FirebaseAuth.getInstance();
}
Which I can then go on the standard flow of of validating the token against Firebase and getting the user details.
Since I'm distributing both the Angular frontend and the Java client to end users, I can't use the Admin SDK.
How do I go about solving this? Is there some other type of flow I should be looking into? or can I make use of the Firebase token somehow?
The Firebase Admin SDK doesn't have the ability to scope its access to a single authenticated user. It's intended for use on backend systems that you control fully. Initialized with a service account, it will have permission to do anything that service account can do. It's not intended to be distributed to end users or any entity that you don't trust with full access to your Firebase project.
When it comes to actually authenticating the end user, Firebase Authentication is only meant to be used in the client apps (Android, iOS, web, and derivative environments).

Why do I need to provide AWS Credentials when using the Cognito SDK?

My Java app is using AWS Cognito user pools. It uses the Amazon SDK to sign users in. EG:
Map<String, String> authParams = new HashMap<>();
authParams.put("USERNAME", email);
authParams.put("PASSWORD", StringUtils.SPACE);
AdminInitiateAuthRequest authRequest = new AdminInitiateAuthRequest()
.withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH)
.withAuthParameters(authParams)
.withClientId(clientId)
.withUserPoolId(poolId);
AdminInitiateAuthResult result = cognitoClient.adminInitiateAuth(authRequest);
This code above will not work without AWS access credentials. Why though? I just want to access the AWS Cognito user pool. Is it absolutely required that I need to pass in AWS credentials into the Java app? Trying to avoid having to either version AWS credentials or manually configure them (or set up some auto-configure mechanism).
You're using adminInitiateAuth, which is a server-side authentication flow. This is how your credentialed backend would authenticate a user.
For client-side authentication flow, you should use initiateAuth, not adminInitiateAuth.
See User Pool Authentication Flow in the Developer Guide.

AWS Cognito GetCredentialsForIdentity

I am trying to use the approach outlined in the following blog article to authenticate a cognito identity to S3 from Java:
https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-4-enhanced-flow/
I have successfully implemented the developer authentication provider and can retrieve a valid OpenId token for my cognito identity. That token works in both the iOS and Android SDKs when uploading/downloading files to S3. Unfortunately, I have not been able to successfully authenticate the same identity to S3 in my Java app. Here is the code I am using:
Map<String, String> logins = new HashMap();
logins.put("cognito-identity.amazonaws.com", cognitoOpenIdToken);
GetCredentialsForIdentityRequest getCredentialsRequest =
new GetCredentialsForIdentityRequest()
.withIdentityId(cognitoIdentityId)
.withLogins(logins);
AmazonCognitoIdentityClient cognitoIdentityClient =
new AmazonCognitoIdentityClient();
GetCredentialsForIdentityResult getCredentialsResult =
cognitoIdentityClient.getCredentialsForIdentity(getCredentialsRequest);
The call to getCredentialsForIdentity fails with the error "com.amazonaws.AmazonClientException: Unable to load AWS credentials from any provider in the chain". This method is documented as a public API that does not require authentication. However, I have noticed that the call succeeds if done from an environment where there are valid IAM credentials configured in the system variables. It fails in environments where that is not the case.
Am I missing something simple?
Have you tried initializing the AmazonCognitoIdentityClient in following manner?
new AmazonCognitoIdentityClient(new AnonymousAWSCredentials());
Otherwise, by design of AWS Java SDK, the service clients look for AWS credentials, because same client can be used for accessing Authenticated APIs as well.
maybe is not that you need to be as another IAM user... but that the user that is running you method has a "deny" on sts:* (or some other actions that you need)

Multiple SSO providers in Spring Boot Auth server

I have read and implemented my own Auth server following this tutorial from Spring. There are multiple SSO providers - Facebook, Github and a custom auth server. In this tutorial, the auth server contains the handling of other SSO providers.
I have a separate resource server that links to my auth server using the following properties:
security.oauth2.resource.userInfoUri=http://localhost:9000/user
I am able to get the token from my auth server using a cUrl command:
curl acme:acmesecret#localhost:9000/oauth/token -d grant_type=password -d username=user -d password=...
{"access_token":"aa49e025-c4fe-4892-86af-15af2e6b72a2","token_type":"bearer","refresh_token":"97a9f978-7aad-4af7-9329-78ff2ce9962d","expires_in":43199,"scope":"read write"}
But what I fail to understand is how can I use the other SSO providers to get such token as well from the auth server? The resource server should not care how did I get the token and whether I am authenticated using Facebook or my custom auth server. It should simply ask the auth server what is the Principal (logged user) and then decide which resources to show him, right?
I don't have any UI and this will be backed for a mobile application so I need to udnerstand how to handle the authentication using REST reqeusts.
If I understand your question correctly,
how can I use the other SSO providers to get such token as well from
the auth server?
This custom Auth server is abstracting out your interaction with FB or Github and issuing you it's own token. The token that your custom Auth server spitting out is not an FB or Github token, it's a token generated by your custom Auth server (After authenticating with FB/Github token).
Then why do we need FB/github?
How else your custom Auth server can identify a person, It sure can use user Id and Password; consider 'login with FB' as another nice option it gives to the user.
How to add other SSO providers like digitalocean in addition to FB and github?
Just do the same as we did for FB and Github (register a client id with digital ocean and then in auth server application, Add client Id and secret in the properties/yaml file etc)
The resource server should not care how did I get the token and
whether I am authenticated using Facebook or my custom auth server. It
should simply ask the auth server what is the Principal (logged user)
and then decide which resources to show him, right?
Yes, your understanding is correct.
Edit (To answer question asked in the comment)
But lets say I log in with Facebook through my Auth server. Where do I
find the token that I can use with the Resource server? Let's say I
have a RestClient and want to make a request to obtain some resource
belonging to a user which went through the Facebook auth process via
my auth server. Where do I find the token to use?
If that's a requirement, I think you can use this example instead; you may not need a custom auth server as such. Whole point of having custom auth server is abstracting out the interaction with FB or github.
Or
If you still want to go with custom auth server direction, then expose an endpoint from Auth server (which will get you the resources you need from FB) and then make use of that from your resource server.

Categories