How to make a RESTful call using Basic Authentication in apache camel? - rest

I have an apache camel application that requires sending log files to an endpoint and this requires Basic Authentication. I was able to pass the authMethod, authusername and authPassword to the url as specified in the camel documentation but the challange I'm having is that I keep getting null response from the endpoint after starting the application.
However, the same endpoint returns response code and response body using postman.
Below is my code:
from("{{routes.feeds.working.directory}}?idempotent=true")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
String fileName = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
File file = exchange.getIn().getBody(File.class);
multipartEntityBuilder.addPart("file",
new FileBody(file, ContentType.MULTIPART_FORM_DATA, fileName));
exchange.getOut().setBody(multipartEntityBuilder.build());
Message out = exchange.getOut();
int responseCode = out.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
log.info("response code "+responseCode);
}
})
.setHeader(Exchange.HTTP_QUERY,
constant("authMethod=Basic&authUsername="+username+"&authPassword="+password+""))
.to(TARGET_WITH_AUTH +"/"+uuid+"/files")
.log(LoggingLevel.DEBUG, "response code >>>>"+Exchange.HTTP_RESPONSE_CODE)
.log(LoggingLevel.INFO, "RESPONSE BODY ${body}")
.end();
Kindly help review and advise further

For HTTP basic authentication I use this before sending a request
<setHeader headerName="Authorization">
<constant>Basic cm9vdDpyb290</constant>
</setHeader>
cm9vdDpyb290 - Encoded Base64 root:root(username and password) string

This was fixed by using httpClient to send my requests with Basic Authentication. Apparently, authMethod in apache camel doesn't send the credentials along with the Post Request and that's why I was getting the initial 401 response code.
Thank y'all for your contributions.

Related

Vertx Web Client throwing HTTP 415 Unsupported Media Type for Multipart/form-data

This service receives the multipart request from mobile client and passes on the request to downstream service for uploading the image. I am seeing 415 Unsupported Media Type in my downstream service
private void makeRequest(HttpRequest<Buffer> httpRequest,
Promise<Object> future,
RequestContext requestContext,
RoutingContext routingContext,
Entry entry) {
MultipartForm multipartForm = MultipartForm.create();
MultiMap attributes = routingContext.request()
.formAttributes();
attributes.forEach(attribute -> {
multipartForm.attribute(attribute.getKey(), attribute.getValue());
});
routingContext.fileUploads()
.forEach(fileUpload -> {
multipartForm.binaryFileUpload(fileUpload.name(), fileUpload.fileName(),
fileUpload.uploadedFileName(), fileUpload.contentType());
});
httpRequest.sendMultipartForm(multipartForm, response -> {
handleResponse(routingContext, future, response, requestContext, entry);
});
}
Getting the below exception
javax.ws.rs.NotSupportedException: HTTP 415 Unsupported Media Type
at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.getMethodRouter(MethodSelectingRouter.java:478)
at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.access$000(MethodSelectingRouter.java:94)
at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter$4.apply(MethodSelectingRouter.java:779)
at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.apply(MethodSelectingRouter.java:371)
API signature of my downstream service
#POST
#Timed
#Path("{userId}/{scope}/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation("Multipart upload of an image")
Can someone please guide what is wrong in my code snippet or is there any setting which needs to be enabled in vertx server or vertx web client?
Thanks,
Nitish Goyal
I was able to resolve this by explicitly setting the header
.putHeader("content-type", "multipart/form-data")

How to retrieve fault information from soap error response using script in SoapUI mock service

I created a mock service in SoapUI. I am using Groovy in this mock service so I can mock some requests, as well as forward other requests to the actual web service I am mocking.
When the web service returns one of three possible fault messages, I am unable to retrieve that actual fault from the soap response.
The mock service Groovy script just replies with the response herebelow (IOException, http status 500).
But when sending a request to the actual web service directly, I get the response I actually would like to get.
Groovy code which forwards the request and retrieve a response:
def soapUrl = new URL("[actual web service]");
def connection = soapUrl.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type" ,"text/html");
connection.setRequestProperty("SOAPAction", "");
connection.doOutput = true;
Writer writer = new OutputStreamWriter(connection.outputStream);
writer.write(soapRequest);
writer.flush();
writer.close();
connection.connect();
def soapResponse = connection.content.text;
// alert.showInfoMessage(soapResponse);
requestContext.responseMessage = soapResponse;
Response using the Groovy scripted mock service:
<soapenv:Body>
<soapenv:Fault>
<faultcode>Server</faultcode>
<faultstring>Failed to dispatch using script; java.io.IOException: Server returned HTTP response code: 500 for URL: [the endpoint url]</faultstring>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
Response when accessing the web service directly (with the same request):
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring> [actual fault message] </faultstring>
<detail> [useful details about the fault] </detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
When using the script, why is the response not the same as if I would retrieve it directly?
Ok I found out I can use the connection (URLConnection) in a different way.
I made some changes based on the accepted answer here.
Now, the actual response, happy or error, is retrieved. So in both cases the web service response is being forwarded to the mock service output. And now I can see the fault info in the response.
...
connection.connect();
// Get the response
HttpURLConnection httpConnection = (HttpURLConnection) connection;
InputStream is;
if (httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
is = httpConnection.getInputStream();
} else {
// Http error
is = httpConnection.getErrorStream();
}
// Read from input stream
StringBuilder builder = new StringBuilder();
BufferedReader buffer = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = buffer.readLine()) != null) {
builder.append(line);
}
buffer.close();
// Forward the response to mock service output
requestContext.responseMessage = builder.toString();

Integration Tests fail with JWT Authorization on OpenLiberty

Integration Tests (production code works well) fail while requesting REST endpoints secured with #RolesAllowed.
Following error is thrown:
[5/20/19 8:44:21:363 CEST] 00000109 com.ibm.ws.security.jaspi.JaspiServiceImpl I CWWKS1652A: Authentication failed with status AuthStatus.SEND_FAILUR for the web request
/banking/users/bed6109f-ef8a-47ec-8fa4-e57c71415a10. The user defined Java Authentication SPI for Containers (JASPIC) service null has determined that the authentication data is not valid.
Project is based on OpenLiberty with JWT. The difference is in the UI part. My UI is based on Angular, so for authentication (JWT issuing) following REST Endpoint is used:
#RequestScoped
#Path("/tokens")
#PermitAll
public class AuthResource {
#Inject
private SecurityContext securityContext;
#Inject
private AuthService authService;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getJwt() {
if (securityContext.isCallerInRole("USER") || securityContext.isCallerInRole("ADMIN")) {
String name = securityContext.getCallerPrincipal().getName();
AuthPojo authPojo = authService.createJwt(name);
return Response.ok(authPojo).build();
}
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
So:
UI (Angular) calls https://localhost:5051/tokens with Header "Authorization: Basic ENCODED_USERNAME_PASSWORD"
Backend responds with newly generated JWT Token in body and Header "Set-Cookie: LtpaToken2=SOME_TOKEN; Path=/; HttpOnly"
UI uses this token for all other requests against REST Endpoints annotated with "#RolesAllowed({"ADMIN", "USER" })"
Once again, in production code, all this schema works well, but Integration Tests fail.
Here is Integration Test code:
public class MyResourceIT {
private static final String URL = "https://localhost:" +
System.getProperty("liberty.test.ssl.port") + "/users/" + USER_ID1;
private String authHeader;
#Before
public void setup() throws Exception {
authHeader = "Bearer " + new JwtVerifier().createAdminJwt(USER_NAME1);
}
#Test
public void getUserAndAccounts() {
Response response = HttpClientHelper.processRequest(URL, "GET", null, authHeader);
System.out.println("My URL: " + URL);
System.out.println("My Header: " + authHeader);
assertThat("HTTP GET failed", response.getStatus(), is(Response.Status.OK.getStatusCode()));
}
}
Looks like the problem why 401 instead 200 is returned is LtpaToken2 Cookie which is not set in Test. Instead Header "Authorization: Bearer JWT_TOKEN" is used, but this doesn't work.
I Expect that Endpoint secured with "#RolesAllowed" should respond with 200 when header "Authorization: Bearer JWT_TOKEN" is provided. Are there some tricks that should be done with a cookie?
UPDATE 2019-05-23
This is the whole project.
Example test is located here. The failing test is ignored
#Test
public void getUserAndAccounts_withJwt_authorized() throws IOException {
Response response = HttpClientHelper.processRequest(URL, "GET", null, authHeader, null);
assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode()));
}
JWT token is created within following class in the #Before annotated method:
private String authHeader;
#Before
public void setup() throws Exception {
authHeader = "Bearer " + new JwtVerifier().createAdminJwt(USER_NAME1);
}
One thing to notice, that project is based on the following project.
Since the CWWKS1652A message was issued without a provider name, this indicates that appSecurity-3.0 is set and that at least a JSR-375 (a.k.a. Java EE Security API Specification) HttpAuthenticationMechanism is configured for the application, either via annotation or bean implementation. This causes an internal JASPIC provider to be created, therefore the null in the CWWKS1652A message, and this provider invokes the configured HttpAuthenticationMechanism that returns a AuthStatus.SEND_FAILURE status.
Please ensure that you intend to use an HttpAuthenticationMechanism and that valid authentication credentials are passed when challenged by this mechanism.
If it is determined that there is no HttpAuthenticationMechanism configured, then determine if there is an external JASPIC provider factory (AuthConfigFactory implementation) set via the authconfigprovider.factory property. In either case, it is the provider that responds with the AuthStatus.SEND_FAILURE seen in the message.

error uploading file HTTP Client & RESTful server

I'm trying to create a HTTP Client to upload a file following this example: http://java.dzone.com/articles/file-upload-apache-httpclient
When I run the application to upload the file on my RESTFul service, I get:
HTTP ERROR 500
Problem accessing /file/upload. Reason:
Server ErrorCaused by:java.lang.NullPointerException
at com.nice.rest.UploadFileService.uploadFile(UploadFileService.java:33)
...
Where line 33 is:
public class UploadFileService {
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail) {
//line 33: String uploadedFileLocation = "/mnt/folder/"+ fileDetail.getFileName();
System.out.println("uploadedFileLocation : "+uploadedFileLocation);
// save it
writeToFile(uploadedInputStream, uploadedFileLocation);
String output = "200 OK<br />" + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
Surprisingly, when I upload a file using a html form it works fine:
form action="http://X.X.X.X:8080/file/upload" method="post" enctype="multipart/form-data"
What's wrong?
thanks!!
When you build your multi-part entity, make sure that the #FormDataParam annotation value contains the name of the part within the multipart.
It looks like the part you're looking for doesn't exist hence the NullPointerException.
Please post your client code if possible showing how you construct the multi-part entity

Apache Wink Client - Test a REST service using form auth

I am trying to use the Wink RestClient to do functional testing on a Rest service endpoint. I use mocks for unit testing but I'd like to functionally test it as an endpoint consumer.
I understand some will object to me calling it a REST endpoint while using form-based auth but that is the current architecture I have.
The majority of the resources I want to test are protected resources and the application (running on Tomcat6) is protected by form authentication. (as in the below web.xml snippet).
What I've tried so far is to make an initial call to an unprotected resource, to obtain the set-cookie header, that contains JSESSIONID, and use that JSESSIONID in the header ( via Resource.cookie() ) in subsequent requests but that does not yield fruit.
web.xml
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/login.html?failure=true</form-error-page>
</form-login-config>
</login-config>
My Wink RestClient code looks like below. All responses are 200, but two things I notice are that the response from the call to /j_security_check/ does not include the jsessionid cookie, and the call to the protected resource said I had a signin failure. The payload for the call to j_security_check was captured directly from a previous successful browser request intercepted.
ClientConfig config = new ClientConfig();
config.setBypassHostnameVerification(true);
RestClient restClient = new RestClient(config);
Resource unprotectedResource = restClient.resource( BASE_URL + "/");
unprotectedResource.header( "Accept", "*/*" );
ClientResponse clientResponse = unprotectedResource.get();
String response = clientResponse.getEntity(String.class);
// get jSession ID
String jSessionId = clientResponse.getHeaders().get("set-cookie").get(0);
jSessionId = jSessionId.split(";")[0];
System.out.println(jSessionId);
// create a request to login via j_security_check
Resource loginResource = restClient.resource(BASE_URL + "/j_security_check/");
loginResource.accept("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
loginResource.header("referer", "http://localhost:8080/contextroot/");
loginResource.cookie( jSessionId );
loginResource.header("Connection", "keep-alive");
loginResource.header("Content-Type", "application/x-www-form-urlencoded");
loginResource.header("Content-Length", "41");
ClientResponse loginResponse = loginResource.post("j_username=*****&j_password=*************");
/* the loginResponse, as this point, does not have the jsessionid cookie, my browser client does */
Resource protectedResource = restClient.resource(BASE_URL + "/protected/test/");
systemResource.accept("application/json");
systemResource.cookie( jSessionId );
ClientResponse systemResponse = systemResource.get();
response = clientResponse.getEntity(String.class);
System.out.println(response);
Any thoughts or experience with using the Wink RestClient to exercise form-auth-protected resources would be greatly appreciated. I suppose I'd entertain other frameworks, I have heard of REST-Assured and others, but since the application uses Wink and the RestClient seems to provide me with what I need, I figured I'd stick with it.
Found the problem, and the solution
j_security_check was responding to my POST request (to authenticate), with a #302/redirect. That was being followed by the wink RestClient, but my JSESSIONID cookie was not being appended to it. That was causing the response (from the redirected URL) to contain a set-cookie header, with a new header. My subsequent calls, into which I inserted the JSESSIONID from the first call, failed, because that cookie was expired. All I needed to do was instruct the RestClient to NOT follow redirects. If the redirect were necessary, I would construct it on my own, containing the appropriate cookie.
Chromium and Firefox carry the cookie from the original request to the redirected request so it's all good.
Here is some code that worked for me, using JUnit4, RestClient from the Apache Wink project (and a Jackson ObjectMapper)
#Test
public void testGenerateZipEntryName() throws JsonGenerationException, JsonMappingException, IOException
{
final ObjectMapper mapper = new ObjectMapper();
final String BASE_URL = "http://localhost:8080/rest";
// Configure the Rest client
ClientConfig config = new ClientConfig();
config.proxyHost("localhost"); // helpful when sniffing traffic
config.proxyPort(50080); // helpful when sniffing traffic
config.followRedirects(false); // This is KEY for form auth
RestClient restClient = new RestClient(config);
// Get an unprotected resource -- to get a JSESSIONID
Resource resource = restClient.resource( BASE_URL + "/");
resource.header( "Accept", "*/*" );
ClientResponse response = resource.get();
// extract the jSession ID, in a brittle and ugly way
String jSessId = response.getHeaders().get("set-cookie").get(0).split(";")[0].split("=")[1];
// Get the login resource *j_security_check*
resource = restClient.resource(BASE_URL + "/j_security_check");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
resource.header("Content-Type", "application/x-www-form-urlencoded");
resource.header("Content-Length", "41");
// Verify that login resource redirects us
response = resource.post("j_username=admin&j_password=***********");
assertTrue( response.getStatusCode() == 302 );
// Grab a public resource
resource = restClient.resource(BASE_URL + "/");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
response = resource.get();
// verify status of response
assertTrue( response.getStatusCode() == 200 );
// Grab a protected resource
resource = restClient.resource(BASE_URL + "/rest/system");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
// Verify resource returned OK
response = resource.contentType("application/json").accept("*/*").get();
assertTrue( response.getStatusCode() == 200 );
// Deserialize body of protected response into domain object for further testing
MyObj myObj = mapper.readValue(response.getEntity(String.class), MyObj.class );
assertTrue( myObj.customerArchived() == false );
}