jpri / android-xmlrpc

Automatically exported from code.google.com/p/android-xmlrpc
0 stars 0 forks source link

HTTP Basic authentication & Pre-emptive Authentication #6

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
I tried to use the client with a server that requires an username and a
password. However, if I use this:

XMLRPCClient client = new
XMLRPCClient("http://username:password@192.168.0.1:8766/");

I get a 401 error. When I use the same argument from python (on an other
system), there are no problems at all.

Original issue reported on code.google.com by avirule...@gmail.com on 19 Mar 2009 at 6:49

GoogleCodeExporter commented 8 years ago
Hmmm, this library uses apache's HttpPost class for socket communication. I 
don't 
know how it handles username:password Uris...

Original comment by psk...@gmail.com on 21 Mar 2009 at 8:12

GoogleCodeExporter commented 8 years ago
Well according to people in the IRC channel, this should be handled correctly 
by the
lib. Do you happen to transform the URL in any way?

Thanks

Original comment by avirule...@gmail.com on 22 Mar 2009 at 12:26

GoogleCodeExporter commented 8 years ago
I was hoping you would have some suggestions on how to fix this. I cannot get 
it to
work, whatever I try. 

Thanks.

Original comment by avirule...@gmail.com on 22 Mar 2009 at 6:44

GoogleCodeExporter commented 8 years ago
Ah, I found out something. Apparently this is also called Basic auth for HTTP. 
The
Apache XML-RPC client seems to support this. 

Will your implementation for Android support this in the short run? 

Thanks

Original comment by avirule...@gmail.com on 24 Mar 2009 at 11:58

GoogleCodeExporter commented 8 years ago
I'm sorry for spamming this page, but I have one more addition. The Apache 
XML-RPC
lib supports this through a method client.addBasicUserName and
client.addBasicPassword, it doesn't support the username:password type either..

Original comment by avirule...@gmail.com on 24 Mar 2009 at 11:59

GoogleCodeExporter commented 8 years ago
for your comment #2: i dont modify url in any way, i pass it to lower stack as 
it 
is...

Original comment by psk...@gmail.com on 26 Mar 2009 at 2:18

GoogleCodeExporter commented 8 years ago
in android there is a package org.apache.http.auth but i have no idea how to 
use it.

maybe you could take a look and try to play with it? 

Original comment by psk...@gmail.com on 26 Mar 2009 at 2:21

GoogleCodeExporter commented 8 years ago
Hey. Yeah, I found out how to do it, I'll modify your code as soon as I have 
some
time and then I'll send it to you. 

Original comment by avirule...@gmail.com on 28 Mar 2009 at 1:22

GoogleCodeExporter commented 8 years ago
I get it to work with this additional constructor for XMLRPCCLINT:

    public XMLRPCClient(URI uri, String username, String password) {
        this(uri);

        ((DefaultHttpClient) client).getCredentialsProvider().setCredentials(
        new AuthScope(uri.getHost(), uri.getPort(),AuthScope.ANY_REALM),
        new UsernamePasswordCredentials(username, password));
    }

Original comment by tobi...@gmail.com on 7 May 2009 at 12:02

GoogleCodeExporter commented 8 years ago
+1
Basic authentication is very easy to add to the library and often mandatory. 

Instead of an extra constructor, I use a method that can be used after 
instantiating
an XMLRPClient object (but before any call of course).

    /**
     * Sets basic authentication on web request using plain credentials
     * @param username The plain text username
     * @param password The plain text password
     */
    public void setBasicAuthentication(String username, String password) {
        ((DefaultHttpClient) client).getCredentialsProvider().setCredentials(
                new AuthScope(postMethod.getURI().getHost(), postMethod.getURI().getPort(),
AuthScope.ANY_REALM),
                new UsernamePasswordCredentials(username, password));
    }

Thanks for this library.

Original comment by erickok@gmail.com on 20 May 2009 at 2:45

GoogleCodeExporter commented 8 years ago
A patch (that can be applied to the current SVN) is attached.

Original comment by erickok@gmail.com on 2 Jun 2009 at 9:54

Attachments:

GoogleCodeExporter commented 8 years ago
For everyone, for who the above solution did not work, the following link might 
be
helpful
http://dlinsin.blogspot.com/2009/08/http-basic-authentication-with-android.html 

Original comment by piotrm...@gmail.com on 25 Oct 2009 at 7:50

GoogleCodeExporter commented 8 years ago
Copy the below text, and then right click on
"src/org/xmlrpc/android/XMLRPCClient.java", select Team -> Apply a patch -> From
clipboard (ensuring the below text is copied). Accept all the defaults.

Index: src/org/xmlrpc/android/XMLRPCClient.java
===================================================================
--- src/org/xmlrpc/android/XMLRPCClient.java    (revision 14)
+++ src/org/xmlrpc/android/XMLRPCClient.java    (working copy)
@@ -12,6 +12,8 @@
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
@@ -88,6 +90,14 @@
        HttpProtocolParams.setUseExpectContinue(httpParams, false);
        client = new DefaultHttpClient();
    }
+
+   public XMLRPCClient(URI uri, String username, String password) {
+        this(uri);
+
+        ((DefaultHttpClient) client).getCredentialsProvider().setCredentials(
+        new AuthScope(uri.getHost(), uri.getPort(),AuthScope.ANY_REALM),
+        new UsernamePasswordCredentials(username, password));
+    }

    /**
     * Convenience constructor. Creates new instance based on server String address
@@ -97,6 +107,10 @@
        this(URI.create(url));
    }

+   public XMLRPCClient(String url, String username, String password) {
+       this(URI.create(url), username, password);
+   }
+   
    /**
     * Convenience XMLRPCClient constructor. Creates new instance based on server URL
     * @param XMLRPC server URL

Original comment by JonTheNiceGuy on 20 Feb 2010 at 9:31

GoogleCodeExporter commented 8 years ago
Patches applied.

Original comment by JonTheNiceGuy on 23 Feb 2010 at 4:41

GoogleCodeExporter commented 8 years ago
I still have problems with basic Authentication...
I have tried with 
XMLRPCClient client = new XMLRPCClient(url, username, password);
and
XMLRPCClient client = new XMLRPCClient(url);
client.setBasicAuthentication(usename, password);
but it is not working for me.

I'm using Android 2.2, and on server side a small python application. 

Original comment by bszabo...@gmail.com on 7 Sep 2010 at 6:08

GoogleCodeExporter commented 8 years ago
Hi Bszabbolcs:

Can you advise what the error is you're getting? Can you provide an idea of 
where the error is occurring? Also, if relevant, can you copy the appropriate 
lines from your httpd access and error logs - sanitised if applicable)?

Also, have you got the version of the code released on or after 2010-02-23?

Lastly, is the website you're calling against SSL encrypted with a self signed 
certificate, as this may cause you some problems.

I've not done anything with this code (or any Android/Java) for several months, 
so I might not be able to help immediately, but this information would be very 
useful to myself or anyone else who will try to help.

Original comment by JonTheNiceGuy on 7 Sep 2010 at 6:36

GoogleCodeExporter commented 8 years ago
I'm at work right now, but when I when I arrive home I will send you the logs.
What can I tell you now is:
I'm using the latest svn version of xmlrpc, but i can try with the version 
provided on Download page.
On server side I'm using a small python application without SSL encryption. 
When I print, in python, the header received, it doesn't contains the line for 
authentication. With a python client it's working.

More info when I arrive home...

Btw this library is great, and thank you for it!

Original comment by bszabo...@gmail.com on 8 Sep 2010 at 5:16

GoogleCodeExporter commented 8 years ago
This is the message from adb logcat

W/DefaultRequestDirector(23742): Authentication error: Unable to respond to any 
of these challenges: {}

I don't have any other message regarding to xmlrpc.

And this is how the header looks at server side:

Content-Type: text/xml
Content-Length: 86
Host: *****
Connection: Keep-Alive

So, there is no Authentication in header...

I will try to make some debugging, but i'm new to Android...

Original comment by bszabo...@gmail.com on 8 Sep 2010 at 5:19

GoogleCodeExporter commented 8 years ago
Note that by default the basic authentication is not preemptive. You will thus 
First get a request without the Authentication header. 

Original comment by erickok@gmail.com on 8 Sep 2010 at 7:26

GoogleCodeExporter commented 8 years ago
So... it is possible that the problem is at the server side?

Original comment by bszabo...@gmail.com on 8 Sep 2010 at 7:59

GoogleCodeExporter commented 8 years ago
I still can't get it to work... I have tried the version from the download 
page, but it still doesn't send the authentication part in the header. Or it 
should be requested by the server?
Can somebody send me a piece of code where the authentication is working?

Original comment by bszabo...@gmail.com on 9 Sep 2010 at 7:18

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
Perhaps we should add another variable to be passed to the function: boolean 
PreemptiveAuth, which if TRUE will activate this function, but which isn't 
enabled by default.

This means that code which isn't already using this, won't get it if they 
update the source, but new code which picks it up can make use of it?

Original comment by JonTheNiceGuy on 12 Sep 2010 at 8:12

GoogleCodeExporter commented 8 years ago
Following the description on this site, the authentication works.
http://dlinsin.blogspot.com/2009/08/http-basic-authentication-with-android.html

Original comment by bszabo...@gmail.com on 13 Sep 2010 at 5:44

GoogleCodeExporter commented 8 years ago
bszabolcs: If you've got a code snippet which works, would you be willing to 
paste it in this ticket, so we can add it to the Wiki, and amend the code to 
incorporate the calls that you made?

Original comment by JonTheNiceGuy on 14 Sep 2010 at 1:07

GoogleCodeExporter commented 8 years ago
It's really simple. Do something like this:

    this.rpcclient = new XMLRPCClient(buildWebUIUrl(), settings.getSslTrustAll());
    if (settings.shouldUseAuthentication()) {
        this.rpcclient.setBasicAuthentication(settings.getUsername(), settings.getPassword());
    }
    this.rpcclient.call("load_start", new String[] { url });

This is taken from my project. Full source code: 
http://code.google.com/p/transdroid/source/browse/trunk/src/org/transdroid/daemo
n/Rtorrent/RtorrentAdapter.java

To do pre-emptive authorization, look for the line 'HttpResponse response = 
client.execute(postMethod);' in the XMLRPCClient.java file and add this just 
before the execute():

    // Force preemptive authentication
    // This makes sure there is an 'Authentication: ' header being send before trying and failing and retrying 
    // by the basic authentication mechanism of DefaultHttpClient
    postMethod.addHeader("Authorization", "Basic " + Base64.encodeBytes((username + ":" + password).getBytes()));

This manually adds the authorization header. Hope this helps.

Original comment by erickok@gmail.com on 14 Sep 2010 at 2:18

GoogleCodeExporter commented 8 years ago
I have defined this innerclass in XMLRPCClient.java:

HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
    public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
        AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
        CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
        HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);

        if (authState.getAuthScheme() == null) {
            AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
            Credentials creds = credsProvider.getCredentials(authScope);
            if (creds != null) {
                authState.setAuthScheme(new BasicScheme());
                authState.setCredentials(creds);
            }
        }
    }    
};

and I have added the first line to activate preemptive authentication:

((DefaultHttpClient) client).addRequestInterceptor(preemptiveAuth, 0);
((DefaultHttpClient) client).getCredentialsProvider().setCredentials(
    new AuthScope(postMethod.getURI().getHost(), postMethod.getURI().getPort(),AuthScope.ANY_REALM),
    new UsernamePasswordCredentials(username, password));

Original comment by bszabo...@gmail.com on 15 Sep 2010 at 12:23

GoogleCodeExporter commented 8 years ago
Thanks for these code snippets erickok and bszabolcs. I'll try and implement 
something around this over the next week or so.

Original comment by jon@sprig.gs on 19 Nov 2010 at 4:06

GoogleCodeExporter commented 8 years ago
The Code snippets are working very well. I implement them because i need them 
for my project. If you tell me how I can push them, I will do that tomorrow ;)

Original comment by j.rehb...@googlemail.com on 23 Nov 2010 at 3:10

Attachments:

GoogleCodeExporter commented 8 years ago
j.rehborn thanks for your code - it's best to attach patches rather than 
complete files, as it helps us to work out what the differences are that you've 
introduced.

I copied your code into the tree, and it introduced an error (around the Base64 
library), so to be honest, as I'd already started on this, I've not looked too 
deeply into fixing the issue in your code, or looking at whether it's a clearer 
and cleaner piece of code. I'll be pushing the patch inspired by erickok's code 
snippet, shortly (as part of a few patches), but in the meantime, here's the 
patch I'll be pushing.

(Note, I've just spotted that I've not credited erickok as inspiration, this 
will be fixed in the push.)

Original comment by jon@sprig.gs on 23 Nov 2010 at 9:21

Attachments:

GoogleCodeExporter commented 8 years ago
This code has been committed, and requires testing.

Original comment by jon@sprig.gs on 24 Nov 2010 at 9:46

GoogleCodeExporter commented 8 years ago
Hey Guys,

i'm pretty new to android-developing but i'm having this íssue as well - even 
after using the patch and trying both - with false and true option at BasicAuth 
Setting, here my code snippet:

                try {
                serverURL = new URL(server+":"+port);
            } catch (MalformedURLException e) {
                System.out.println("Invalid URL - could not connect!");
            }
            myServer = new XMLRPCClient(serverURL);
            myServer.setBasicAuthentication("myuser", "mypw", true);
                state = (HashMap<String,Integer>)                                                                 myServer.call("Tester.getStatement", params );

I don't really know how to solve this problem. I attached my webserver (Apache 
XML-RPC java) code. The Serverside see's both username and password as null.

Original comment by canyumusak on 27 Dec 2010 at 8:09

Attachments:

GoogleCodeExporter commented 8 years ago
Hi canyumusak,

I'm not certain whether the issue you've mentioned is linked to this issue - 
can you advise what happens when you try and run your script? Can you provide 
any log output? Do you see the access attempt occur on your web server? Are you 
able to provide any packet capture of what happens when you try to make your 
connection?

Also, are you able to try the following:

try {
  serverURL = new URL(server+":"+port);
} catch (MalformedURLException e) {
  System.out.println("Invalid URL - could not connect!");
}
myServer = new XMLRPCClient(serverURL, "myuser", "mypw");
state = (HashMap<String,Integer>) myServer.call("Tester.getStatement", params );

The current version of the code, while it's not covered in the documentation, 
does support client creation method.

Original comment by jon@sprig.gs on 27 Dec 2010 at 10:18

GoogleCodeExporter commented 8 years ago
Hey jon,

i am currently running the same client in a normal JRE, using the XML-RPC 
Client creation of apache.
I tried several combinations (myServer = new XMLRPCClient(serverURL, "myuser", 
"mypw"), myServer = new XMLRPCClient(new 
URL(http://myuser:mypw@192.168.2.24/));, etc..).
My Server can't seem to recognize the username and password.

I tried to look at the logcat log now. It returns me the attached error (i 
think it's the fatal one). Should i continue posting here?

greetings,
Geki

Original comment by canyumusak on 27 Dec 2010 at 11:41

GoogleCodeExporter commented 8 years ago
I tried several combinations.
I attached my Logcat results. I suppose, that this XML-RPC Client is not 
compatible with the apache XML-RPC Server. 

What XML-RPC java alternative should I use?

greetings,

Geki

Original comment by canyumusak on 28 Dec 2010 at 12:18

Attachments:

GoogleCodeExporter commented 8 years ago
What i forgot to write: The Server gives me this error:

28.12.2010 01:15:25 org.apache.xmlrpc.server.XmlRpcErrorLogger log
SCHWERWIEGEND: Not authorized
org.apache.xmlrpc.common.XmlRpcNotAuthorizedException: Not authorized
    at org.apache.xmlrpc.server.ReflectiveXmlRpcHandler.execute(ReflectiveXmlRpcHandler.java:84)
    at org.apache.xmlrpc.server.XmlRpcServerWorker.execute(XmlRpcServerWorker.java:46)
    at org.apache.xmlrpc.server.XmlRpcServer.execute(XmlRpcServer.java:86)
    at org.apache.xmlrpc.server.XmlRpcStreamServer.execute(XmlRpcStreamServer.java:200)
    at org.apache.xmlrpc.webserver.Connection.run(Connection.java:208)
    at org.apache.xmlrpc.util.ThreadPool$Poolable$1.run(ThreadPool.java:68)
28.12.2010 01:22:21 org.apache.xmlrpc.server.XmlRpcErrorLogger log

Original comment by canyumusak on 28 Dec 2010 at 12:28

GoogleCodeExporter commented 8 years ago
Certainly this library can't handle URLs in the format 

http://username:password@hostname/path/to/xmlrpc.svc

but it should be able to cope with

http://hostname/path/to/xmlrpc.svc

although I also noticed in your URL creation above (in comment 32), you've used 

serverURL = new URL(server+":"+port);

Is there any reason you're quoting port numbers? Given our inflexibility in the 
authentication portion, it would probably be worth trying (if you're using a 
different port) running the service on straight port 80, and trying just using 
the straight URL (no ports or auth details)?

Thus your code would be: 

myServer = new XMLRPCClient(server_url, "user", "passwd");

I'm not saying this will fix it, but it's something else to try?

Original comment by jon@sprig.gs on 28 Dec 2010 at 12:32

GoogleCodeExporter commented 8 years ago
I get absolutely the same error.
Trying to get it to work "anyhow" - i set the auth-method to always return 
true. It works this way.
My port was 8080, changing it to 80 didn't change the error or the way it 
behaves. 
Unfortunately i am programming this with access to critical data, hence i can't 
leave it without any authentication.

I am thinking about migrating away from apache xml-rpc in java, if this solves 
the error. Are there good alternatives?

Original comment by canyumusak on 28 Dec 2010 at 1:59

GoogleCodeExporter commented 8 years ago
News:
Using myServer = new XMLRPCClient(server_url, "user", "passwd"); ends in the 
error i wrote above.

myServer = new XMLRPCClient(server_url); connects succesfully (with no Auth 
requested)

Original comment by canyumusak on 28 Dec 2010 at 2:31

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
I'm no longer able to commit time to this project, and as such, I am removing 
myself from any tickets I've previously been involved in.

Original comment by jon@sprig.gs on 14 Sep 2011 at 12:17