Issue while accessing WooCommerce Rest API from OkHttp based app - android

I want to build an android client that can interact with the WooCommerce based site using the Rest Api provided by WooCommerce
This is my android code. I am using OkHttp library for networking.
public class MainActivity extends AppCompatActivity {
OkHttpClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String cred = Credentials.basic("ck_...","cs_...");
OkHttpClient client = new OkHttpClient
.Builder()
.build();
Request req = new Request
.Builder()
.addHeader("Authorization",cred)
.url("http://10.0.2.2:8080/woocom/wp-json/wc/v2/products")
.build();
client.newCall(req).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d("api resp", "onFailure: ");
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("Api resp", "onResponse: "+response.body().string());
}
});
}
}
This is the error log after running the app
com.example.android.woocommerceapiintegration D/Api resp: onResponse: {"code":"woocommerce_rest_cannot_view","message":"Sorry, you cannot list resources.","data":{"status":401}}
What am I doing wrong here. I tried out the NodeJS client provided by WooCommerce which works fine.
Also I cannot access the rest api via curl according to the command given in the docs
Can someone tell me what I am doing wrong ?
Update: The selected answer is what needs to be done in production environments, and is the technically right thing to do. If you want to avoid the hassle of OAuth while on a development server, I have answered it seperately.

The 401 code indicates an authorization issue with your connection. Specifically your issue is caused by your usage of BasicAuth with an HTTP connection.
The WooCommerce REST API Documentation indicates that BasicAuth is only supported for HTTPS connections, and HTTP connections must use OAuth 1.0a "one-Legged" authentication to "ensure" your credentials aren't intercepted by an attacker.
It's important to note that even with OAuth 1.0a, an HTTP connection will never be truly secure and it's highly recommended to switch your app over to a secure HTTPS connection.
Meanwhile, in order to get your code working, you'll have to implement the OAuth 1.0a authentication method for your Android app.
You can find a complete set of instructions and a complete project example of OAuth 1.0a implementation for Android here. The GitHub Page has an excellent guide with step-by-step instructions on using the library linked above. Just make sure that when using the code provided you make sure to account for the fact that you're using OKHttp. Luckily, the author has commented the code in the instructions very well and makes a note of changes to make when using something like OkHttp.
You could use Retrofit and simply write an Interceptor which takes care of the 'nitty-gritty' part as detailed in the documentation here.
You could also follow the step by step guide detailed in the WooCommerce Documentation here to generate your OAuth signature and finally encodedUrl and then pass it to your http client. This processs involves: (see the Documentation for detailed specs for each section)
Collecting the request method and URL
Collecting all oauth_* parameters and encoding them into a single string using percent encoding and correct ordering. For Example (taken from WooCommerce Docs):
oauth_consumer_key=abc123&oauth_signature_method=HMAC-SHA1
Create the base string for the signature by joining the values from 1 and 2. For example: (once again from Docs):
GET&http%3A%2F%2Fwww.example.com%2Fwp-json%2Fwc%2Fv2%2Forders&oauth_consumer_key%3Dabc123%26oauth_signature_method%3DHMAC-SHA1
Finally generate the signature using HMAC-SHA1 (HMAC-SHA256 is also supported).
Personally I would recommend either the first or second approach. "No need to reinvent the wheel".
EDIT:
You can look at this question which discusses how you can use self-signed certificates in a local dev environment with OkHttp.

Thanks akseli for answering my question.I've also awarded you the bounty and thanks for adding to my knowledge. Despite everything, I've found a simple solution to this problem.
My concern was that while development, We generally don't have an https based server and hence have to go through that tedious OAuth based process which won't be used is production anyway as the server we will probably use will be https enabled.
So, to use basic authentication while on an http dev server, you need to go to [your wordpress directory]/wp-content/woocommerce/includes/api. Find out class-wc-rest-authentication.php. This class handles the api authentication. Find the authenticate function which looks like this
public function authenticate( $user_id ) {
// Do not authenticate twice and check if is a request to our endpoint in the WP REST API.
if ( ! empty( $user_id ) || ! $this->is_request_to_rest_api() ) {
return $user_id;
}
if ( is_ssl() ) {
return $this->perform_basic_authentication();
}
return $this->perform_oauth_authentication();
}
comment out the condition is_ssl and simply return $this->perform_basic_authentication(), so that in any case, basic authentication is performed.
Note:This is a hack just to avoid the hassle of OAuth authentication while in dev environment and is not at all recomended in production.

Related

OkHttp Request returns cached result, for different X Auth Tokens

I'm working on an Android App, where i'm using Retrofit to communicate with a rest API.
This API provides a login, to get X Auth Tokens.
I have an interceptor to set this tokens for every request like this:
#Override
public void intercept(RequestFacade request) {
request.addHeader("X-Auth-SOFTTOKEN", softToken);
request.addHeader("X-Auth-HARDTOKEN", hardToken);
request.addHeader("X-Auth-USER", username);
}
I can observe a strange behaviour, where i get Cached responses for the old User, although the X Auth Tokens are different and i should get the response for the new logged in user.
If i add this piece of code to my rest API interface methods, it works.
#Headers("Cache-Control: no-cache")
I can't find any hints if this is expected behaviour or not. I thought the cache should only beeing triggered, if the request is exactly the same.
Have a look at this answer: https://stackoverflow.com/a/35993722/3964585 and from there also http RFC - https://www.rfc-editor.org/rfc/rfc7231#section-7.1.4
In short - caches have to take headers into consideration when server indicates so with "Vary" header. Alternative way for server is to use Cache-control header directives.
Seems that in your case server is returning incorrect responses. If you can, fix that, if not you can not use http cache.

How to implement android RESTful client with Robospice (or something like this) + OAuth?

How to implement Robospice (or something like this) + OAuth?
Maybe someone can share link to examples of good practices for creating RESTful android clients? I can't figure the architecture of RESTful app with OAuth, which cover all problems with activity's lifecycle.
Of course I know about Virgil Dobjanschi "Google I/O 2010 - Android REST client applications". With some Libraries like Robospice it is very easy to implement. But what if app uses OAuth for authorization to service? What libraries for OAuth could be useful? where store access token? How execute some requests synchronously? etc. ...
I am looking for complete code examples or at least advices about design and architecture.
It depends. Are you talking about OAuth 1 or OAuth 2? For the former, you could use signpost. For the latter, you could use RoboSpice + Google Http Client + Google OAuth Client Library.
If you use Google Http Client as your network library, what you need to do is to create your own HttpClientSpiceService based on GoogleHttpClientSpiceService, which you can find in RoboSpice. Then, you need something like this:
public static HttpRequestFactory createRequestFactory() {
HttpTransport httpTransport = AndroidHttp.newCompatibleTransport();
return httpTransport.createRequestFactory(new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) {
// TODO: authorize or sign request...
// Note that this will authorize/sign ALL the requests you make,
// so you will probably want to improve on that.
}
});
}
The rest is really up to you, but the basics are to implement a way to provide third-party log-in, get the required token and set up the OAuth library of your choice.

App Engine endpoint with Retrofit

Would like to use Retrofit for handling network requests between Android Client and GAE endpoints.
GAE endpoints give Client/Server endpoint libraries to handle all the networking and also Oauth2 authentication which is nice.
Retrofit helps well for asynchronous call, cancellation, parallel calls...so is better than android client asynctask.
So can this Retrofit lib be configured with Appengine GAE endpoints or need to go through normal GAE servlet?
Just to clarify my question and make answers clear for any who read this :
I had for my App :
Client side : cloud endpoint library generated by google plug in for eclipse
Back end side GAE : different API with methods coded in JPA such as :
#ApiMethod(name = "insertMyShareItem")
public ShareItemData insertMyShareItemData(ShareItemData shareitemdata) {
logger.log(Level.SEVERE, "insertMyShareItem");
}
Advantages of google cloud endpoint was endpoint libray , easy use of Auth2 and automatically use of secure connections via HTTPS
Now I want to give up Async task in order to implement Retrofit or Volley. I understood I cannot use google cloud endpoint anymore and need to transform my methods on GAE Back end side in methods which extends HttpServlet so I can access them by URL call with normal setup of Retrofit.
Which means now I need to care :
how I pass my object to Retrofit and how I retrieve them on back end
how I transform Retrofit HTTP call in a HTTPS call for secure connection
how I implement and manage Auth2 and tokens between Client and GAE back end to establish secure authentication.
This is what I understood from search and below answers.Thks
Use the Google Cloud API URL as the base URL and proceed with the normal setup of Retrofit. I don't think it is a big deal. Here is a link to a tutorial that could help you get started with Retrofit.
[source]

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.

How do I authenticate/validate an Android app on an App Engine Server with OAuth 2?

I have a simple application that lets a user draw pictures. There are Android, IOS, and web-based versions. I also let users store their pictures on our App-engine servers and I want them to be able to collaborate with other users. I want to use Google accounts for authentication and the basis of some permission scheme.
I do not know how to validate/authenticate a user’s Google account on android (or IOS). I am hoping somebody can help or point me in the right direction. Here is what I understand so far:
On the Web-based client, I just use Google-web toolkits UserService. However for my app-engine servlets i'm not sure what I should use. Currently the servlets have code like this:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
OAuthService oauth = null;
oauth = OAuthServiceFactory.getOAuthService();
User user = oauth.getCurrentUser();
// Do stuff
}
In my android application I think I'm supposed to do something like:
1) Get the Account from the AccountManager
2) Call:
accountManager.getAuthToken
(account, // Account
"oauth2:https://www.googleapis.com/auth/userinfo.profile",//AUTH Token Type
null, // Options
this, // Activity
new MyAccountsManagerCallBack(), // call-back
null); // Handler
This will give me authorization token.
3) ?? profit ??
This is where I am lost. Do I send this authorization token as a clear-text query parameter to my app-engine server, then make a request from the web server to the userinfo/profile api? That doesn’t seem secure.
Is there some way to make the pervious code with OAuthService work?
The samples for OAuth 2 use the Google task API, however I want to use my app-engine API. I’ve found information for OAuth 1 using cookies, webviews, title, etc, but nothing on OAuth 2, and none of them really tell me how to validate server side.
I really have no clue what I should be doing here. I would appreciate any assistance.
To clarify, this is an example of my java servlet served on app engine:
public class ServletSecureData extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
UserService usersrvc = null;
usersrvc = UserServiceFactory.getUserService();
User user = usersrvc.getCurrentUser();
if(user == null)
throw new IOException();
Random r = new Random(System.currentTimeMillis());
int num = r.nextInt(10);
PrintWriter out = response.getWriter();
out.printf("Security !! %s radioactive man! %d", user.getEmail(), num);
out.close();
}
}
This servlet was protected with a security constraint defined in the web.xml file. I wanted to be able to access this servlet using an android client. I thought that I had to used Oauth but it turned out I needed to use an older deprecated service ClientLogin
I based my implementation off the code from this site: http://blog.notdot.net/2010/05/Authenticating-against-App-Engine-from-an-Android-app

Categories

Resources