>Is there any HTTP proxying/redirection involved in your setup?
No. The only proxy is the SPARQL proxy that I'm coding. It is based on the work
of wimmic team ( http://wimmics.inria.fr/projects/shi3ld/ ).
This is my code :
The query engine Http add to the HTTP Header ("Authorization", "Basic
<username>:<password>") where user informations are 64Bits encoded.
My test consist in sending request to the proxy ( no redirection involved, the
user credentials check is done by the proxy ).
For the sparql queries ( SELECT/ASK/DESCRIBE/CONSTRUCT ) I use this code in
order to extract credentials :
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
protected String[] extractCredentials(HttpServletRequest req){
String auth = req.getHeader("Authorization");
if( auth == null || !(auth.toUpperCase().startsWith("BASIC")) ){return
null;}
return this.decode(auth.substring(6)).split(":");
}
private String decode(String s) {
return StringUtils.newStringUtf8(Base64.decodeBase64(s));
}
The UpdateProcessRemoteForm don't add anything to header during my test. I do
this :
UpdateRequest update = UpdateFactory.create(queryString);
UpdateProcessRemoteForm exec = (UpdateProcessRemoteForm)
UpdateExecutionFactory.createRemoteForm(update, service);
exec.setAuthentication("[email protected]", "test".toCharArray());
exec.execute();
And as there is no header corresponding to the key "Authorization" my proxy
send a 407 error ( authentication required ).
>>>>>Request contains following fields :
>>>>>In headers :
>>>>>content-lenght : 273
>>>>>content-type : application/x-www-form-urlencoded; charset=UTF-8
>>>>>host : localhost:8080
>>>>>conection : Keep-Alive
>>>>>user-agent: Apache-HttpClient/4.2.3 (java 1.5)
Maybe your code is working but work in an other way ?
VAISSE-LESTEVEN Arthur.
>I added simple basic auth support to Fuseki and wrote unit tests that
>verified that authentication is working correctly.
>
>It would be useful to know what error code/messages you get with the
>latest SNAPSHOTs?
>
>Is there any HTTP proxying/redirection involved in your setup?
>
>The applyAuthentication() code scopes provided credentials to the given
>service URI so if the server is responding with a 401 Unauthorized on a
>different URI from the original request then HTTP Client may be failing to
>attempt to pass any credentials at all in response to the servers
>challenge and simply bailing out and throwing up the 401 error
>
>Rob
>
>
>On 6/25/13 2:44 AM, "Arthur Vaïsse-Lesteven" <[email protected]> wrote:
>
>>
>>Hi again.
>>
>>It seems that the bug is still present. The HTTPheader not contains
>>basicAuthentification informations. What test did you do about the new
>>httpOp ? I may doing it in a wrong way :/
>>
>>After the debugged applyAuthentication in HttpOp, there is the following
>>line : "HttpResponse response = httpclient.execute(httppost,
>>httpContext);"
>>
>>And I think that the HttpClient.execute method doesn't use the
>>authentication information available in his Credential provider.
>>
>>Rob : "Don't forget you can always check out and do a mvn install locally"
>>Ho yes, I'll do that next time!
>>
>>VAÏSSE-LESTEVEN Arthur.
>>
>>
>>>Hmmm, that is a little weird
>>>
>>>I just forced a rebuild and the latest build does have the change in it,
>>>not sure what happened there. Sometimes the Apache build servers are
>>>just a little flaky.
>>>
>>>Don't forget you can always check out and do a mvn install locally
>>>
>>>Rob
>>>
>>>From: Arthur Vaïsse-Lesteven
>>><[email protected]<mailto:[email protected]>>
>>>Reply-To: "[email protected]<mailto:[email protected]>"
>>><[email protected]<mailto:[email protected]>>, Arthur
>>>Vaïsse-Lesteven <[email protected]<mailto:[email protected]>>
>>>Date: Monday, June 24, 2013 5:26 AM
>>>To: "[email protected]<mailto:[email protected]>"
>>><[email protected]<mailto:[email protected]>>
>>>Subject: Re: Tr : Basic Authentication for SPARQL Update
>>>
>>>Hi Rob,
>>>
>>>It's a little confusing.
>>>
>>>You modified the HttpOp class in the release number 34 on the maven repo
>>>[1], but this modification isn't present in the last version ( 38 ) as
>>>you can see in the java file joined to this mail.
>>>
>>>The add of "client.setCredentialsProvider(provider);" line 400 probably
>>>solve the problem but I'm not able to test it as it isn't present in the
>>>last released version of ARQ.
>>>
>>>( The trunk version of your SVN seems to contains this code too ).
>>>
>>>Thanks for your work.
>>>
>>>VAISSE-LESTEVEN Arthur.
>>>
>>>
>>>[1]
>>>https://repository.apache.org/content/repositories/snapshots/org/apache/j
>>>ena/jena-arq/2.10.2-SNAPSHOT/
>>>________________________________
>>>De : Rob Vesse <[email protected]<mailto:[email protected]>>
>>>À : "[email protected]<mailto:[email protected]>"
>>><[email protected]<mailto:[email protected]>>
>>>Envoyé le : Vendredi 21 juin 2013 19h35
>>>Objet : Re: Tr : Basic Authentication for SPARQL Update
>>>
>>>The latest SNAPSHOTS now have the fix, you may need to add -U to your mvn
>>>calls if you have recently updated SNAPSHOTs to get the very latest
>>>
>>>Please test and confirm whether this resolves the issue
>>>
>>>Rob
>>>
>>>
>>>On 6/21/13 9:13 AM, "Rob Vesse"
>>><[email protected]<mailto:[email protected]>> wrote:
>>>
>>>>Nice catch
>>>>
>>>>Yes I appear to have made an error, I never associated the created
>>>>credentials provider with the HTTP Client
>>>>
>>>>Filed as JENA-475 (https://issues.apache.org/jira/browse/JENA-475)
>>>>
>>>>I will commit a fix ASAP and you should be able to pick up a
>>>>2.10.2-SNAPSHOT build in a few hours with the fix, if you can test with
>>>>the snapshot and report if this resolves the issue that would be great.
>>>>
>>>>You can verify whether the fix has gone into the snapshots by looking at
>>>>https://builds.apache.org/job/Jena__Development_Test/changes and seeing
>>>>if
>>>>there is a build listed where the commit messages mention JENA-475
>>>>
>>>>Rob
>>>>
>>>>
>>>>
>>>>On 6/20/13 11:51 PM, "Arthur Vaïsse-Lesteven"
>>>><[email protected]<mailto:[email protected]>>
>>>>wrote:
>>>>
>>>>>Hi Rob, I'm in trouble with the basic authentication process ( I'm now
>>>>>using ARQ 2.10.1 )
>>>>>
>>>>>
>>>>>In one hand the Queries work like this :
>>>>>when we calls one of the 4 method execX of a queryExecution, the
>>>>>QueryEngineHTTP calls makeHttpQuery, and after few steps this code line
>>>>>is executed :
>>>>> httpConnection.setRequestProperty("Authorization", "Basic "+y) ;
>>>>>where y contains userName:password 64Bits encrypted.
>>>>>
>>>>>This make the http request header contains the Key, Value couple :
>>>>>"Authorization" "Basic username:password".
>>>>>
>>>>>I'm OK with this.
>>>>>
>>>>>In the other hand, the update seem to handle Basic Authentication in a
>>>>>different way.
>>>>>
>>>>>I used this code :
>>>>>
>>>>>UpdateRequest update =
>>>>> UpdateFactory.create(queryString);
>>>>>UpdateProcessRemoteForm exec = (UpdateProcessRemoteForm)
>>>>>UpdateExecutionFactory.createRemoteForm(update, service);
>>>>>exec.setAuthentication("[email protected]<mailto:[email protected]>",
>>>>>"savaillon".toCharArray());
>>>>>
>>>>>And I'm unable to retrieve the usename and the password.
>>>>>Request contains following fields :
>>>>>In headers :
>>>>>content-lenght : 273
>>>>>content-type : application/x-www-form-urlencoded; charset=UTF-8
>>>>>host : localhost:8080
>>>>>conection : Keep-Alive
>>>>>user-agent: Apache-HttpClient/4.2.3 (java 1.5)
>>>>>In params :
>>>>>update : my update
>>>>>No attribute.
>>>>>
>>>>>I tried to follow in the ARQ library the path of my username and
>>>>>password, and finally they transited to the applyAuthentication in
>>>>>HttpOp.
>>>>>
>>>>>This method create a CredentialsProvider and set the credentials
>>>>>username
>>>>>and
>>>>> password. But this method has a void return type, and I don't see any
>>>>>communication point with the rest of the HttpOp code.
>>>>>
>>>>>Do I missed something ?
>>>>>
>>>>>VAÏSSE-LESTEVEN Arthur.
>>>>>
>>>>>
>>>>>>I was using the 2.9.2 ARQ version. I'll update to 2.10.1.
>>>>>>Thanks for your quick answer and for your work Rob!
>>>>>>
>>>>>>VAÏSSE-LESTEVEN Arthur.
>>>>>>
>>>>>>
>>>>>>>What version of ARQ are you using?
>>>>>>>
>>>>>>>I put changes in place which went into the 2.10.1 release which
>>>>>>>should
>>>>>>>permit easy HTTP auth on SPARQL updates. Both
>>>>>>>UpdateExecutionFactory.createRemote() and
>>>>>>>UpdateExecutionFactory.createRemoteForm() return an instance derived
>>>>>>>from
>>>>>>>UpdateProcessRemoteBase which has a setAuthentication() method
>>>>>>>
>>>>>>>If you are using a version of ARQ prior to 2.10.0 there is no common
>>>>>>>base
>>>>>>>class but both UpdateProcessRemote and UpdateProcessRemoteForm
>>>>> would still
>>>>>>>have a setHttpContext() method which allows you to pass in a
>>>>>>>HttpContext
>>>>>>>which can be used to pass in authentication settings using the
>>>>>>>HttpClient
>>>>>>>APIs. Even with 2.10.1 you can still choose to use this method
>>>>>>>particularly if you need to pass complex credentials.
>>>>>>>
>>>>>>>Rob
>>>>>>>
>>>>>>>
>>>>>>>On 6/18/13 8:10 AM, "Arthur Vaïsse-Lesteven"
>>>>>>><[email protected]<mailto:[email protected]>>
>>>>>>>wrote:
>>>>>>>
>>>>>>>>Hi,
>>>>>>>>
>>>>>>>>
>>>>>>>>The remote execution of SPARQL queries offer the
>>>>>>>>setBasicAuthentication
>>>>>>>>fonctionality(1). I'm using it; and when I tried to use it with
>>>>>>>>SPARQL
>>>>>>>>Update it appears that SPARQL Update doesn't handle Authentication.
>>>>>>>>I would like to know, do it exist any way to do the same thing in
>>>>>>>>ARQ
>>>>>>>>? I
>>>>>>>>writted some code by extending 2 apache classes, but it would be
>>>>> better
>>>>>>>>to just use the API. Do you intend to not allow
>>>>>>>>basicAuthentification
>>>>>>>>?
>>>>>>>>It is incompatible with http basic authentication ? There are only
>>>>>>>>24hours per day and you don't had the time to do it yet ?
>>>>>>>>
>>>>>>>>Do this functionality is planed ?
>>>>>>>>
>>>>>>>>____________________________________________________________________
>>>>>>>>__
>>>>>>>>_
>>>>>>>>_
>>>>>>>>
>>>>>>>>(1) What i can write :
>>>>>>>>
>>>>>>>>[...]
>>>>>>>>
>>>>>>>>
>>>>>>>>QueryEngineHTTP exec = (QueryEngineHTTP)
>>>>>>>>QueryExecutionFactory.createServiceRequest(endpoint_URL, query);
>>>>>>>>exec.setBasicAuthentication(user, password);
>>>>>>>>
>>>>>>>>exec.exec...
>>>>>>>>
>>>>>>>>[...]
>>>>>>>>
>>>>>>>>(2)What I want to write :
>>>>>>>>
>>>>>>>>[...]
>>>>>>>>UpdateProcessRemote exec =
>>>>> (UpdateProcessRemote)
>>>>>>>>UpdateExecutionFactory.createRemote(update, endpoint_URL);
>>>>>>>>exec.setBasicAuthentication(user, password);
>>>>>>>>
>>>>>>>>exec.excute();
>>>>>>>>
>>>>>>>>[...]
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>I tried to custom the UpdateProcessRemote class to allow (2). This
>>>>>>>>currently don't work on my computer, but it seem's to be due to a
>>>>>>>>maven
>>>>>>>>version conflict at level of HttpClient. This class must be
>>>>>>>>compatible
>>>>>>>>with current version of Jena.( I set my modifications in bold ).(
>>>>>>>>also
>>>>>>>>downlodable at : http://arthurvaisse.free.fr/classes/ )
>>>>>>>>
>>>>>>>>Thank you,
>>>>>>>>VAÏSSE-LESTEVEN Arthur.
>>>>>>>>
>>>>>>>>
>>>>>>>>____________________________________________________________________
>>>>>>>>__
>>>>>>>>_
>>>>>>>>_
>>>>>>>>
>>>>>>>>public class UpdateProcessRemote
>>>>> implements UpdateProcessor{
>>>>>>>>
>>>>>>>> private String user = null ;
>>>>>>>> private char[] password = null ;
>>>>>>>>
>>>>>>>> private final UpdateRequest request ;
>>>>>>>> private final String endpoint ;
>>>>>>>>
>>>>>>>> public UpdateProcessRemote(UpdateRequest request , String
>>>>>>>>endpoint
>>>>>>>>)
>>>>>>>> {
>>>>>>>> this.request = request ;
>>>>>>>> this.endpoint = endpoint ;
>>>>>>>>
>>>>>>>> }
>>>>>>>>
>>>>>>>> @Override
>>>>>>>> public void setInitialBinding(QuerySolution binding)
>>>>>>>> {
>>>>>>>> throw new ARQException("Initial bindings
>>>>> for a remote update
>>>>>>>>execution request not supported") ;
>>>>>>>> }
>>>>>>>>
>>>>>>>> @Override
>>>>>>>> public GraphStore getGraphStore()
>>>>>>>> {
>>>>>>>> return null ;
>>>>>>>> }
>>>>>>>>
>>>>>>>> @Override
>>>>>>>> public void execute()
>>>>>>>> {
>>>>>>>> String reqStr = request.toString() ;
>>>>>>>> HttpOpCustom.execHttpPost(endpoint,
>>>>>>>>WebContent.contentTypeSPARQLUpdate, reqStr, user, password);
>>>>>>>> }
>>>>>>>>
>>>>>>>> //comes from QueryEngineHTTP.
>>>>>>>> public void
>>>>> setBasicAuthentication(String user, char[] password)
>>>>>>>>
>>>>>>>> {
>>>>>>>> this.user = user ;
>>>>>>>> this.password = password ;
>>>>>>>> }
>>>>>>>>____________________________________________________________________
>>>>>>>>__
>>>>>>>>_
>>>>>>>>_
>>>>>>>>
>>>>>>>>I added this functions to HttpOp to create my custom HttpOp :
>>>>>>>>
>>>>>>>> //Just added credentials in parameters
>>>>>>>> public static void execHttpPost(String url, String contentType,
>>>>>>>>String content, String user, char[] password)
>>>>>>>> {
>>>>>>>> execHttpPost(url, contentType, content, null, null, user,
>>>>>>>>password) ;
>>>>>>>>
>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> //Just added credentials in parameters
>>>>>>>> public static void execHttpPost(String url, String contentType,
>>>>>>>>String content,
>>>>>>>> String acceptType, Map<String, HttpResponseHandler>
>>>>>>>>handlers,
>>>>>>>> String user, char[] password)
>>>>>>>> {
>>>>>>>> StringEntity e = null ;
>>>>>>>> try
>>>>>>>> {
>>>>>>>> e = new StringEntity(content, "UTF-8") ;
>>>>>>>>
>>>>> e.setContentType(contentType) ;
>>>>>>>> execHttpPost(url, e, acceptType, handlers, user,
>>>>>>>>password)
>>>>>>>>;
>>>>>>>> } catch (UnsupportedEncodingException e1)
>>>>>>>> {
>>>>>>>> throw new ARQInternalErrorException("Platform does not
>>>>>>>>support required UTF-8") ;
>>>>>>>> } finally { closeEntity(e) ; }
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> public static void execHttpPost(String url, HttpEntity
>>>>>>>>provider,
>>>>>>>> String acceptType, Map<String, HttpResponseHandler>
>>>>> handlers,
>>>>>>>> String user, char[] password)
>>>>>>>> {
>>>>>>>> try {
>>>>>>>> long id = counter.incrementAndGet() ;
>>>>>>>> String requestURI = determineBaseIRI(url) ;
>>>>>>>> String baseIRI = determineBaseIRI(requestURI) ;
>>>>>>>>
>>>>>>>> HttpPost httppost = new HttpPost(requestURI);
>>>>>>>>
>>>>>>>> if ( user != null || password !=
>>>>> null){
>>>>>>>> if(user==null || password == null){
>>>>>>>> log.warn("Only one of user/password is set") ;
>>>>>>>> }
>>>>>>>> //this code come from httpQuery
>>>>>>>> StringBuffer x = new StringBuffer() ;
>>>>>>>> byte b[] =
>>>>>>>>x.append(user).append(":").append(password).toString().getBytes("UTF
>>>>>>>>-8
>>>>>>>>"
>>>>>>>>)
>>>>> ;
>>>>>>>> String y = Base64.encodeBase64String(b) ;
>>>>>>>> //this single code line is mine
>>>>>>>> httppost.addHeader("Authorization", "Basic "+y);
>>>>>>>> }
>>>>>>>> if ( log.isDebugEnabled() )
>>>>>>>> log.debug(format("[%d] %s %s",id
>>>>>>>>,httppost.getMethod(),httppost.getURI().toString())) ;
>>>>>>>>
>>>>>>>> if (
>>>>> provider.getContentType() == null )
>>>>>>>> log.debug(format("[%d] No content type")) ;
>>>>>>>>
>>>>>>>> // Execute
>>>>>>>> HttpClient httpclient = new DefaultHttpClient();
>>>>>>>> httppost.setEntity(provider) ;
>>>>>>>> HttpResponse response = httpclient.execute(httppost) ;
>>>>>>>> httpResponse(id, response, baseIRI, handlers) ;
>>>>>>>>
>>>>>>>>
>>>>> httpclient.getConnectionManager().shutdown();
>>>>>>>> } catch (IOException ex)
>>>>>>>> {
>>>>>>>> ex.printStackTrace(System.err) ;
>>>>>>>> }
>>>>>>>> finally { closeEntity(provider) ; }
>>>>>>>> }