Custom IoT Endpoint - android

We need to use a custom IoT endpoint due to firewall restrictions and needing to utilize Static Ips. We followed this AWS doc to get our endpoint with static Ips.. From here we are attempting to call the CreateKeysAndCertificate via Java. Now when we call IoT with our custom domain name, iot.custom.domain.name.com, with the regular Java SDK it works fine. However, whenever we try to use the Android SDK and call setEndpoint with our custom domain we get the following error
com.amazonaws.services.iot.model.ResourceNotFoundException: Not Found (Service: AWSIot; Status Code: 404; Error Code: ResourceNotFoundException
Any help or guidance on this would be appreciated.

When using the Android SDK for establishing IOT connections, the CreateKeysAndCertificateRequest API is available through the AWSIotClient class. If you are using the AWSIotClient for creating new certs/keys, the SDK places this request on the generic iot.<region>.amazonaws.com endpoint. The setEndpoint method just allows you to change the region. This is because the request goes to the Control plane, whereas the endpoint that you have created would mostly likely be on the Data plane. There is no way around to create new certs/keys using the AWSIotClient on the custom endpoint.
There is an alternate option that you can make use of. Almost all "requests" that you place on the IOT endpoint are messages that are published to "reserved topics". If you open up the Java SDK's PublishCreateKeysAndCertificate API, you will see that it is ultimately publishing a message over a reserved topic. You can do something similar on Android using the Android SDK as well.
First, you will have to establish an authenticated connection. We cannot use CognitoCredentialsProvider because of that auth request going to the Control Plane. Instead, you can use the provisioning certificates for the first time authentication. This is through provision certificates generated for a Provisioning Fleet. You can create a Provisioning Fleet and use those certificates in your device's keystore (or, a PKCS12 cert file). Using that, you can create a new awsIotMqttManager object and publish a message on the reserved topic meant for creating new certs/keys. You can also subscribe to reserved topics meant for receiving the "accepted"/"rejected" responses for this request.
TL;DR
Create an awsIotMqttManager using the provision certs
Subscribe to topic for listening for accepted/rejected response for CreateKeysAndCertificates request
Publish a message over the reserved topic meant for CreateKeysAndCertificates
Register the thing using the ownershipToken received in the response
Store the new certs and use them for all future connections (make sure the policy attached to the certs have the necessary permissions)

Related

How to force MQTT broker to NOT clean session from Android Paho client?

I'm trying to use MQTT (Paho library on Android, mosquitto message broker on a linux server) to pass moves in a turn-based game, replacing a custom server I wrote years ago. Its simplicity and pub-sub design seem perfect: each device subscribes to a unique id as "topic" and communicates that as its "address." Then other devices can reach it by publishing to that address.
It works perfectly in my test Linux client (connecting using the mosquitto-dev library on Ubuntu). And it works perfectly on Android WHEN THE ANDROID APP IS RUNNING. In the Linux client case, if a message is sent while the app isn't running or connected the app receives the message as soon as it does connect and subscribe. On Android, however, this doesn't happen. Only messages sent (or resent) by another client while the android client is subscribed are ever delivered.
I'm new to MQTT, but it seems pretty clear that the "cleanSession" connection parameter is what controls this: unless you "clean" a session, you get everything that was published to your topic while you were not subscribed. On the Linux client side, passing "true" to mosquitto_new(..., clean_session, ...) does indeed prevent my Linux client from getting pre-connection messages. But on the Android side, calling .setCleanSession(boolean) has no effect when the MqttConnectOptions instance is passed to .connect().
I'm using 1.1.+ of paho. Per the tags in the repo at https://github.com/eclipse/paho.mqtt.android.git, v1.1.1 is the latest.
implementation "org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.+"
implementation "org.eclipse.paho:org.eclipse.paho.android.service:1.1.+"
I suspect that this is simply a bug in the Android Paho library (which doesn't seem to have been worked on in four years.) But I hope I'm wrong! Is there a way to accomplish what I want?
Alternatively, is there a better library? The googling I've done suggests that in spite of its age Paho is still what most Android devs are using to speak MQTT.
Thanks!
About the cleanSession flag.
The Client and Server can store Session state to enable reliable messaging to continue across a sequence of Network Connections. This bit is used to control the lifetime of the Session state.
If CleanSession is set to 0, the Server MUST resume communications with the Client based on state from the current Session (as identified by the Client identifier). If there is no Session associated with the Client identifier the Server MUST create a new Session. The Client and Server MUST store the Session after the Client and Server are disconnected. After the disconnection of a Session that had CleanSession set to 0, the Server MUST store further QoS 1 and QoS 2 messages that match any subscriptions that the client had at the time of disconnection as part of the Session state. It MAY also store QoS 0 messages that meet the same criteria.
More about cleanSession on : https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html
If I understand correctly your requirement, then indeed you need to use clenSession=true. You can also try publishing and subscribing with QoS=0. Some brokers do not store QoS=0 messages, mosquitto as well. (as per https://mosquitto.org/man/mqtt-7.html)
I've found a workaround, and in the process confirmed my suspicion that the MqttAndroidClient class is broken in not honoring that setting. Instead of using MqttConnectOptions I tried using MqttAsyncClient. The code changes are trivial, though underneath there's considerable change as the Android client knows about and uses background Services. With the simple change of using this different class, I'm able to connect & subscribe and immediately receive all messages that were published while I was not connected.

Unable to validate issuer when trying to access API

so here's a quick explanation of my issue - my current setup is and IdentityServer4 implementation with ASP.NET Core Identity, an API resource protected by it and a Xamarin.Android application that is the client. My current issue is that the client(Android) cannot get anything from the API because of the following error(from the API logs):
"Bearer" was not authenticated. Failure message: "IDX10205: Issuer validation failed. Issuer: 'http://10.0.2.2:5000'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'http://127.0.0.1:5000'."
Basically, since I'm using the Android emulator, in order to call something that's on localhost on my machine, I need to use the 10.0.2.2 URL for it. Then the problem pops up - the Identity Server is fine with authenticating, I can login fine, I get an access token, but after that I need to call the API. And that's where the error happens - it's expecting an issuer that is with the same authority(127.0.0.1:5000) but receives the 10.0.2.2:5000, which is the authority for the Android client.
So, my question is - is there a way to somehow specify that 10.0.2.2 is also a valid issuer, or do I have to start thinking about deploying both the API and the Identity Server just so I can test the client. I'd really like it if there was a way to have the whole solution running on my local machine rather than having to deploy for every little thing I want to try out.
Any help will be appreciated very much.
First: Given the standard, you manage just one Issuer.
Are you managing your own Identity / Token generation? It sounds like this isn't the case.
You could customize your API for creating your tokens explicitly. Then, you can indicate a global Issuer (like your project url) so anyone can validate against the same.
var token = new JwtSecurityToken(
issuer: "http://my-perfect-proj.net",
claims: ...,
notBefore: DateTime.Now,
expires: DateTime.Now.AddHours(1),
signingCredentials: ...)
);
After your token is created and sent, validate your incoming request based on your tastes (checking time, user's data, issuer).
ASP.NET Core JWT Bearer Token Custom Validation
Creating RESTful API with Authentication
EDIT: Using Xamarin and Visual Studio on the same machine, didn't gave me this kind of problems but in that case, I was using Visual Studio Emulator. You could give it a try and avoid doing other types of workarounds.
So, I managed to work around the issue by simply running the Web part of it so it's visible on my local network. What I did in more detail - in the Program.cs where I create the host, I use the .UseUrls("http://*:5001") method, and then I run the app with dotnet run.
In this way your app is accessible in your local network via the IP address of your machine and the port you've specified. Also, in order for this to work, you'd have to define a new Outbound Rule in your Firewall to allow traffic through that port you're using. Hope this helps someone else as well, this turned out to be the easiest way to get what I need to work, and that's after fighting with IIS for a while trying to get it to work through there as well.
Short answer: In IIS, don't leave the site binding host name set as blank.
Longer explenation:
I received a similar error, but could see that for some reason it was trying to match the issuer domain name vs IP (the domain does point to the IP, but I guess it tries to validate the two strings). I could see this error after allowing logging : IdentityModelEventSource.ShowPII = true.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException:
IDX10205: Issuer validation failed. Issuer: 'http://ec2XXXXXom'. Did
not match: validationParameters.ValidIssuer: 'http://34.111.111.29' or
validationParameters.ValidIssuers: 'null'. at
Microsoft.IdentityModel.Tokens.Validators.ValidateIssuer(String
issuer, SecurityToken securityToken, TokenValidationParameters
validationParameters)
In IIS I previously had the host name set as blank (I am using the server name as domain name) - and therefore it set the issuer using the IP of the server. When I specifically set the site domain name, it worked.

Passbook / Wallet pkfile Android Auto-Update

I am currently working on a pkpass library for Android. There is one point that I cannot figure out. The Apple's PassKit Web Service Reference specifies how to register a device for automatic updates. This seems to work only with iOS devices.
However, there are a couple of apps out there for Android that are able to register for automatic updates somehow. Wallet Passes | Passbook and Pass2U Wallet for Passbook for instance.
I created a demo pkpass file using PassSource's API. When I update the file on their website, those apps get notified somehow and then show a notification to the user.
This is the behavior I'm trying to create but I cannot figure out for the life of me is what URL with which parameters to call.
I tried every possible combination of values for:
POST request to: webServiceURL/version/devices/deviceLibraryIdentifier/registrations/passTypeIdentifier/serialNumber
Parameters
webServiceURL
The URL to your web service, as specified in the pass.
version
The protocol version—currently, v1.
deviceLibraryIdentifier
A unique identifier that is used to identify and authenticate this device in future requests.
passTypeIdentifier
The pass’s type, as specified in the pass.
serialNumber
The pass’s serial number, as specified in the pass.
Header
The Authorization header is supplied; its value is the word ApplePass, followed by a space, followed by the pass’s authorization token as specified in the pass.
Payload
The POST payload is a JSON dictionary containing a single key and value:
pushToken
The push token that the server can use to send push notifications to this device.
as specified on the apple documentation.
I also studied Walletpasses Documentation and Pass2U Documentation
Help is greatly appreciated!
Thanks!

Protecting my Google App Engine API Endpoints

I have been doing a lot of research recently on securing my app engine. Currently, I've been reading through the question below and the links in that question:
How do I restrict Google App Engine Endpoints API access to only my Android applications?
However, it doesn't answer my problem. My question is similar to the question above, restricting access to my endpoint API to only my app. The guy seemed to have got it working when he inputs a correct email into the credentials.
My question is if I can achieve the same results without having to input any credentials. I want it so that only my app can use my endpoint API so to prevent other apps from abusing it and using up my quota. I already got a client id for my android application, and have placed it within my #API annotation. To test if it worked, I made a random value for the client id in the #API notation of another api class. However, my app was still able to use methods from both class. Any help?
-Edit-
From reading from the docs and researching further, the endpoint way of authorizing apps is by authenticating the user and for my API to check if user is null. My question is that in the process of authenticating the user, is Google somehow able to read my app's SHA1 fingerprint and authorize it to its list of client ids? If so, how can I replicate this process in my endpoint so that I check the SHA1 fingerprint of the app making the request and compare it to a set value? I don't understand the mechanics behind the endpoints very well, so correct me if I am understanding this wrong.
If the android app has access, then the user has access. A motivated party has many options for inspecting your protocol, including putting the device behind transparent proxy or simply running the app through a debugger. I do suggest running your app through ProGuard before publishing, as this will make the process [a bit] more difficult.
Ultimately, you'll need to make your appengine API robust against untrusted parties. This is simply the state of the web.
How you can protect your endpoint API is described here: http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html
The secret is that you request a token from Google Play using the following scope: audience:server:client_id:9414861317621.apps.googleusercontent.com where 9414861317621.apps.googleusercontent.com is your ClientId.
Google Play will look up the id at your endpoints app and return a Google-signed JSON Web Token if it finds the id. Then you pass that id in with your request. Above article says you should pass it in with the body. I would possibly rather add another parameter for that because otherwise you can't pass your own entities anymore. Anyway, your server backend receives the token, and you ask Google as described if it is authentic, before you process the API request.
If you pass in the token using an extra parameter, you can catch it on the server side by adding HttpServletRequest to your endpoint signature and then using request.getHeader("Yourname") to read it out. Make sure you never add the parameter as a URL parameter as it may be logged somewhere.
public void endpointmethod(
// ... your own parameters here
final HttpServletRequest request
) throws ServiceException, OAuthRequestException {
request.getHeader("YourHeaderName") // read your header here, authenticate it with Google and raise OAuthRequestException if it can't be validated
On the Android side you can pass in your token when you build the endpoint api, like this, so you don't have to do it with each and every request:
Yourapiname.Builder builder = new Yourapiname.Builder(AndroidHttp.newCompatibleTransport(), getJsonFactory(), new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
httpRequest.setHeader(...);
}})
Hope this helps you make your endpoints API secure. It should.

HttpAuthorizer() for Pusher

I need a private channel on Pusher in order to enable a bunch of Android clients to communication with each other. Pusher was recommended to me, although it is really complicated. I've read all the docs many times, so I'm hoping someone (Mr. Leggetter?) could give me a hand.
I've installed the Pusher Android JAR on the client and am able to subscribe to public channels that I trigger from the "Event Creator" (very neat), but in order to get the private channel working, in order to trigger events, I need this:
HttpAuthorizer authorizer = new HttpAuthorizer("http://example.com/some_auth_endpoint");
PusherOptions options = new PusherOptions().setAuthorizer(authorizer);
Pusher pusher = new Pusher( YOUR_APP_KEY, options );
According to http://pusher.com/docs/authenticating_users, the HttpAuthorizer() needs a URL that points to an app server that is going to respond with a JSON authentication token. Do I have to set up my own app server to provide authentication, like the example at https://raw.github.com/pusher/pusher-android-example/master/src/com/pusher/android/example/MainActivity.java, or can Pusher provide this? This seems like something Pusher should provide.
In the Ruby server code example for my app (why is there no Java?) I see this: Pusher.url = "http://{key}:{secret}#api.pusherapp.com/apps/{app_id}". This URL, however, does not exist. I tried it in HttpAuthorizer() and got a java.io.FileNotFoundException. (I just found the "Enable Clients Events" checkbox under Settings - checking it did not help, but I'm guessing that's an important step.)
If I have to set up my own app server for authentication, I'd like to use Java with GAE. http://pusher.com/docs/authenticating_users#implementing_private_endpoints has a Python/GAE example, but no Java, and I don't know Python. Is there a library for this? Will https://github.com/marcbaechinger/gae-java-libpusher# do the trick? It doesn't seem like it would.
token. Do I have to set up my own app server to provide authentication, like the example at https://raw.github.com/pusher/pusher-android-example/master/src/com/pusher/android/example/MainActivity.java, or can Pusher provide this?
You need to set up your own authentication server. The point in this is to allow you to authenticate subscriptions. This means you can authenticate the user in any way you see fit, against any existing or new authentication mechanism you may use e.g. user sessions (more applicable to web apps) or authentication tokens your own application may provide upon initial connection (via some username/password login to your system).
In the Ruby server code example for my app (why is there no Java?) I see this: Pusher.url = "http://{key}:{secret}#api.pusherapp.com/apps/{app_id}". This URL, however, does not exist.
There is a Java server library but Pusher don't directly maintain that. It's a community contributed one.
I'm not sure where you got the URL from. Maybe from the Web API reference, but unless you are writing your own Pusher Web API library I wouldn't expect you to be using that URL directly. There are Pusher and contributed helper libraries for that sort of thing.
If I have to set up my own app server for authentication, I'd like to use Java with GAE. http://pusher.com/docs/authenticating_users#implementing_private_endpoints has a Python/GAE example, but no Java, and I don't know Python. Is there a library for this? Will https://github.com/marcbaechinger/gae-java-libpusher# do the trick?
Yes, you need to set up your own authentication server. You could create a client-side authorizer, but that would mean exposing your app_secret in client code - which you shouldn't do.
The PusherUtil class provides a number of helper methods that you could use to add subscription authentication support to the library. But - you are right - it doesn't appear to offer this functionality.
The Pusher Play module (also Java) does appear to have an appropriate method so this could be ported. See:
https://github.com/regisbamba/Play-Pusher#generating-the-authentication-string
I don't work for Pusher any more, but I would be happy to contribute to an improved Java library.

Categories

Resources