Rob, as a sidenote for this thread and some previous ones about
uniform HTTP access in Jena, I wanted to show how easily
authentication can be done using Jersey (implementation of JAX-RS).
This is from Graphity subclass of UpdateProcessRemote:
@Override
public void execute()
{
Client client = Client.create();
WebResource wr = client.resource(endpointURI);
if (user != null && password != null) client.addFilter(new
HTTPBasicAuthFilter(user, password));
ClientResponse response =
wr.type(WebContent.contentTypeSPARQLUpdate).
accept(WebContent.contentTypeResultsXML).
post(ClientResponse.class, request.toString());
}
Martynas
graphityhq.com
On Wed, Jun 26, 2013 at 3:00 AM, Rob Vesse <[email protected]> wrote:
> 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 then 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) ; }
>>>>>>>> }
>