JSch: How to ssh into a server using ssh-keys - android

I want to ssh into a server from behind another ssh server. The gateway server requires a username/password and I can do this. I am using a tunnel to get into the next server, but this one requires only an ssh key. I've generated the key through PuTTY, so it exists for my username but I'm not sure how to retrieve it for my Java program. Is it a configuration? i.e. setConfig("userauth.publickey", "com.jcraft.jsch.UserAuthPublicKey") then how do I use this or something else? Documentation seems to be sparse and I appreciate any help. Anything I've tried gives me an error :"Auth fail" when I connect this session
Thanks!
The tunnel method I use is: http://sourceforge.net/apps/mediawiki/jsch/index.php?title=ProxySSH so thanks to the guy who wrote it!
For context, I'd like to read/write to a server at my school from my Android phone.

To enable public-key authentication, you have to use one of the JSch.addIdentity methods.
These take the public and private key in the OpenSSH key format - so make sure you export it from PuTTY in this format. (JSch doesn't understand PuTTY's native format, though you could write an adapter implementing the Identity interface, parsing it yourself).
The identities added to JSch are global, not per-session. This is normally not a problem, as JSch will try all authentication methods which are supported both by itself and the server in order, and public-key authentication is normally before password authentication.
All authentication methods need a user name (usually the name of the account to be logged into).
With public-key authentication, the public key must be somehow previously available to the server. For OpenSSH's sshd, the public key should be listed in ~/.ssh/authorized_keys. (If you have only one public key, simply copy it to this file, if you have multiple ones (each of which will be allowed), each should be on one line.)
So it should work out-of-the box after setting the identity.
If you want to make sure the first session uses password authentication and the second (tunneled) one uses public-key, you can use the per-session configuration, overriding the global one:
tunnelSession.setConfig("PreferredAuthentications", "password");
innerSession.setConfig("PreferredAuthentications", "publickey");
(These are comma-separated lists, here of one element each.)
About the ProxySSH example, that is by me (with some help by JSch's author, Atsuhiko Yamanaka). I should add this information to the Wiki page, maybe.

Related

Custom IoT Endpoint

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)

How to make Android app login requests all appear as one IP

I am developing a native Android app that must interact with a Salesforce org through a SOAP API. Currently, for users of the app to login, they must provide a security token alongside their username and password. This makes the login/signup process uncomfortably long and complicated. As far as I can see, the only solution is to whitelist every IP address in my Salesforce org. I would have thought this is a security issue, so I was wondering if there was a better solution.
As far as I can tell, one solution could be to configure my app to log in through a proxy, and then just whitelist the address of that proxy. It was while researching this that I found this https://serverfault.com/questions/514716/whats-the-minimum-required-squid-config-to-make-a-public-proxy-server that made me think that perhaps there is some other more established way to do this, that I am not aware of.
Basically, my question is, is there any way for an android app running on any phone to make requests to an external API that all appear to come from one IP address (possibly through a proxy server) (without doing anything "dodgy")?
Looks like you're solving wrong problem. Why do you want to bypass SF security features so badly.
Try logging in to SF using REST, not SOAP. The session id you'll receive can be used in any API. So if you log in with OAuth2 you might not need security token. You'd need consumer id and secret (but that's just a pair of values you securely generate in SF, not bound to any particular user. You can even use production's values to login to sandboxes).
There's A LOT of reading if you want to do it right. And some prerequisite step of creating a "Connected App". If possible check if your Android library doesn't have something built-in for OAuth logins (to SF, Gmail, Facebook, LinkedIn, Twitter... you can find OAuth/OpenId in few places)
If you want pure background connection without user realising he's communicating with Salesforce - probably the "Username and password" OAuth flow is best for you. That should be minimal changes in your code compared to SOAP login call. It's weak in a sense you still need to have a password (either user's password or some dedicated integration account) - but there's chance that no security token will be needed. Give it a go (examples below) and check user's login history for errors.
If your users have proper SF accounts then maybe another OAuth flow is better. One that ideally displays them with SF login page they trust and just redirects back to your app when login succeeded. (you probably saw something like this if you recently used SF Data Loader?). That way your app doesn't see the password, just the result. And it'll work even if your client wants to use custom domain, decides to enable Single Sign-On...
Sorry, authentication, authorization are massive topics. But there is a better way so I'd want you to make a conscious decision before you code yourself into a corner... If help materials are too dry / too new & full of keywords then maybe try passing some trailheads:
https://trailhead.salesforce.com/content/learn/modules/identity_basics
https://trailhead.salesforce.com/content/learn/modules/api_basics (read intro and REST API part)
https://trailhead.salesforce.com/en/content/learn/modules/mobile_sdk_introduction/mobilesdk_intro_security
Your SOAP login looks probably like that:
POST
https://test.salesforce.com/services/Soap/c/45.0/
HEADERS
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
PAYLOAD
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">
   <soapenv:Body>
      <urn:login>
         <urn:username>uptonogood#example.com</urn:username>
         <urn:password>Nice_Try!111 + security token</urn:password>
      </urn:login>
   </soapenv:Body>
</soapenv:Envelope>
Corresponding OAuth login (forced to return XML although mobile app should "like" JSON better so if you want - ditch the Accept header I've added)
POST
https://test.salesforce.com/services/oauth2/token
HEADERS
Content-Type:application/x-www-form-urlencoded
Accept:application/xml
PAYLOAD
grant_type=password&
client_id=3MVG9fTLmJ60pJ5JaGv0NNHD5nh6P...&
client_secret=3437814...&
username=uptonogood#example.com&
password=Nice_Try!111
The proper way to do this would be to have your own backend through which you proxy your requests.
e.g.:
Android app -> Your backend -> Salesforce

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.

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.

Amazon AppStore Submission Failed: "Sensitive information like password is echoed in clear text without encryption"

I've submitted an application to the amazon app store, and it was rejected with the following details:
Sensitive information like password is echoed in clear text without
encryption
Obviously, not a great thing ... however I've reviewed the application code. The user's password is stored in the private preferences as an MD5 hash (it goes straight from textbox to md5 hash to prefs, and is not logged or written anywhere as plaintext.
When we post requests to our web API (via http), we post a header with the username, and a hash of the following concatenated string (nonce + timestamp + passwordHash) (along with some other bits).
I assume it has to do with the data in the header, but as it's a hash of a hash that we're posting (which the server compares with its own digest of the password he knows), I'm not really sure why they'd have a problem with that.
How can I troubleshoot this failure?
Just to close the loop on this. I ended up emailing amazon, and they gave me more details ... turns out I was submitting the password in cleartext on the registration page. everything else was fine.
We ended up getting an ssl cert and using https to register the user and it was approved. hope that helps someone else out there :-)
Your hashing scheme is broken. By hashing the password and then using that hash like you do, you just redefined what the plaintext password is.
One consequence of this is that anybody who gets access to your database can login to any account, since you stored the plaintext of your derived password.
I'd either:
1) Store the hash(Using bcrypt or similar) on the server. Then send the plain text password to the server and rely on SSL for transport security.
2) Use SRP. But DON'T implement this yourself. It's notorious for being hard to implement correctly. It's very easy to make a mistake and ending up with an insecure login.
Both of them are more secure than your current system.

Categories

Resources