Jersey: "Broken pipe" instead of HTTP 401 Unauthorized - java

I have a POST request code that uploads a file. It uploads files correctly but fails with "Broken pipe" instead of 401 Unauthorized that I expect when I provide an incorrect API key.
I have used Postman to verify that our server sends 401 Unauthorized when a wrong API key is provided.
I am under the impression that my client code still tries to send something to the stream even though the server has already closed the connection after it had sent the 401 Unauthorized.
This is the code I am using:
try {
return target
.path("storage")
.path("upload")
.request()
.header("Authorization", apiKeyHeader)
.header("App-Type", type)
.post(Entity.entity(Files.newInputStream(file.toPath()), APPLICATION_OCTET_STREAM), String.class);
} catch (IOException e) {
e.printStackTrace(); // <-- exception comes here
}
I have also tried upgrading Jersey to the latest version available: 2.27 but that didn't change anything.
javax.ws.rs.ProcessingException: java.net.SocketException: Broken pipe (Write failed)
at org.glassfish.jersey.apache.connector.ApacheConnector.apply(ApacheConnector.java:496)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:278)
at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$1(JerseyInvocation.java:767)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:229)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:414)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:765)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:456)
at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:357)
at org.comcom.rest.api.resource.v2.AppStorageResource.uploadFile(AppStorageResource.java:70)
This is my pom.xml config:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.23.1</version>
</dependency>

Related

Webflux and Resilience4j retry issue

wanted to ask a basic question about webflux and resilience4j's retry.
We are running Java SpringBoot with Webflux and Resilience4J (not Spring Cloud Circuit Breaker).
While running the application its giving error (Somehow full stack trace is not coming for me) :
due to exception [reactor.core.publisher.Mono.retryWhen(Ljava/util/function/Function;)Lreactor/core/publisher/Mono;]
Code to build the Retry bean is as follows (we are not using YAML based configuration):
#Bean
public Retry retryConfig(ResilienceCCMConfig resilienceCCMConfig) {
RetryConfig config = RetryConfig.custom().maxAttempts(5)
.waitDuration(Duration.of(1, SECONDS))
.retryExceptions(ServerException.class)
.ignoreExceptions(ClientException.class)
.build();
return RetryRegistry.of(config).retry("retry-config", config);
}
Now we are calling our web client's POST method as below with bean injected from above :
#Autowired
private Retry retryConfig;
return webClient.post().uri(url)
.headers(httpHeaders -> getItemHeaders(httpHeaders, tenantId, bannerId, correlationId))
.body(itemServiceRequestMono, ItemServiceRequest.class)
.retrieve()
.onStatus(HttpStatus::isError, clientResponse -> {
LOGGER.error("Error");
if (clientResponse.statusCode().is5xxClientError()) {
throw new Exception("Something went wrong ");
}
return Mono.empty();
})
.bodyToMono(MyResponse.class)
.transform(RetryOperator.of(retryConfig))
.onErrorResume(ex -> myFallbackMethod(ex));
POM dependency :
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-reactor</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId> io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.6.1</version>
</dependency>
Please help .

Spring Boot Resource Server Invalid Token

I'm trying to configure OAuth2 for a Spring project. I used jdbc authentification and my authorization server and resource server are two separate API. My issue is now with the microservices. I'm trying to use this shared authorization server to authenticate the microservices. I can get access_token from the token endpoint.
I can check the access_token from the check_token endpoint.
My resource server configuration:
#SpringBootApplication
#EnableCircuitBreaker
#EnableDiscoveryClient
#EnableResourceServer
public class ProductApiServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApiServiceApplication.class, args);
}
}
And application.yml:
security:
oauth2:
client:
client-id: saba-product-api-service
client-secret: secret123
resource:
id: saba-product-api-service
token-info-uri: http://localhost:9999/uaa/oauth/check_token
And REST controller:
#GetMapping("/user/me")
public Principal user(Principal principal) {
return principal;
}
When I call the /user/me endpoint I get invalid_token.
My Resource Server log:
And my Authorization Server log:
What is wrong with my code?
Update
The problem is because of this code:
I had the same issue. In my case, I was using spring cloud oauth2, Hoxton.SR4 release and it was working. So, I change to Hoxton.SR6 and the issue was throwed. My Authoriation Server also was a Eureka's client, and the issue was origined cause this dependency. There was one dependência inside Eureka Client, named jackson-dataformat-xml, and because it the return of check_token endpoint was converted in xml instead json. When RemoteTokenServices called check_token, and the resulta was a xml, it culdn't decerialized in map<String,Object> the right way. If you had more than one aud, scope or authorities, it picked the last one. And the active propertie was trated as string. In my case I solved the issue excluding in Authorization Server the dependency mentioned from Eureka Client, like this:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
Finally, I replaced
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
with
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
// gh-838
if (map.containsKey("active") && !"true".equals(String.valueOf(map.get("active")))) {
logger.debug("check_token returned active attribute: " + map.get("active"));
throw new InvalidTokenException(accessToken);
}

Springboot error for Eureka with browsers showing xml instead of json

I have created one microservice using Java8 and SpringBoot using Maven.
Lets call it as MicroServiceA
It has controller which returns ResponseEntity object as below:
#RestController
#RequestMapping("/api")
public class MicroserviceAController {
#GetMapping(value = "/all")
public ResponseEntity<ServiceAResponseWrapper<List<ServiceADto>>> getAll() {
ServiceAResponseWrapper<List<ServiceADto>> wrapper =
new ServiceAResponseWrapper<List<ServiceADto>>(ServiceAResponseStatus.SUCCESS,findAll());
return new ResponseEntity<ServiceAResponseWrapper<List<ServiceADto>>>(wrapper,HttpStatus.OK);
}
public static List<ServiceADto> findAll() {
//returns list of ServiceADto objects
}
}
When I start this service and verify it in any browser: http://localhost:8073/api/all/ , I get JSON response displayed.
Now if I want to introduce my service to EUREKA service registry then I will need to do following changes.
Create EUREKA server microservice. I start it - http://localhost:8761/
Make changes to MicroserviceA as follows -
Go to pom.xml and add dependency
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
go to application.yml and add this:
eureka:
client:
registerWithEureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka/
As soon as I start my service then I start seeing it on server http://localhost:8761/
Now I again go to browser and try to check my microservice http://localhost:8073/api/all/ What I see is XML and not JSON.
I even tried to fix it by modifying my Microservice Controller by adding
annotation to my method:
#Produces( { MediaType.APPLICATION_JSON} )
But with that also I see XML and not JSON.
Am I missing something or its normal behavior with EUREKA ? If yes, how do I fix it?
If you are using older version of spring cloud starter, you might need to exclude Jackson dataformat XML dependency
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
There are two potential solutions for this:
First: exclude the jackson-dataformat-xml dependency from all spring-cloud-starter-* artifacts if your application has nothing to do with XML conversions. One exclusion example from spring-cloud-starter-netflix-eureka-client is below. For my case, I had to exclude Jackson XML dependency from spring-cloud-starter-netflix-ribbon, spring-cloud-starter-openfeign and spring-cloud-starter-netflix-eureka-client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
Second: If you want to support both XML and JSON responses. You can pass Accept: header with the request to your API.
For getting JSON response:
curl -X GET \
http://localhost:8073/api/all/ \
-H 'Accept: application/json'
For getting XML response:
curl -X GET \
http://localhost:8073/api/all/ \
-H 'Accept: application/xml'
Hi I myself never used Eureka but from a quick search there is a ready to use API that converts the XML to json as Eureka uses XML and not json because json can’t hold attributes.
Link to the site explaining how to do this ->
https://automationrhapsody.com/json-format-register-service-eureka/amp/
Hope this helps you out

Integration error jersey-multipart and swagger

I have a JAX-RS webservice using Jersey-1. There is only a single method at the moment, which sends mails with attachment. The attachment has to be provided as a multipart form data.
#POST
#Path("/mail")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response sendInfomailWithAttachment(
#Context ServletContext context,
#Context SecurityContext security,
#QueryParam ("FROM") String senderAddress,
#QueryParam ("SUBJECT") String subject,
#QueryParam ("TO") String toRecipients,
#QueryParam ("CC") String ccRecipients,
#QueryParam ("BCC") String bccRecipients,
#QueryParam ("noCopy") boolean sendNoCopy,
#FormDataParam("attachment") InputStream fileInputStream,
#FormDataParam("attachment") FormDataContentDisposition contentDispositionHeader,
#FormDataParam("attachment") FormDataBodyPart fileBody,
#FormDataParam("content") FormDataBodyPart content
){}
The method works fine. But when I try to integrate swagger, I always get this error(s):
SEVERE: Missing dependency for method public javax.ws.rs.core.Response ... throws java.lang.Exception at parameter at index 8
(this error is thrown for param 9, 10 and 11 as well)
in combination with
SEVERE: Method, public javax.ws.rs.core.Response ... throws java.lang.Exception, annotated with POST of resource, class com.mywebservice.MyClass, is not recognized as valid resource method.
If I throw out the FormDataParam stuff, the service starts normally, also with the swagger integration.
I use
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>1.17</version>
</dependency>
and
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-jersey-jaxrs_2.10</artifactId>
<version>1.3.4</version>
</dependency>
Is there any known interference? Anything else I could do to come around this?
As I found out, it was a maven resolution problem.
The swagger lib 1.3.4 uses jersey-core-1.3 and jersey-server-1.3, which has been chosen by maven. Instead, I needed it in 1.17 like the jersey-servlet and jersey-multipart version. So I had to add those two dependencies to the pom to make the maven dependency resolution use 1.17 over 1.13.

how to handle multipart request using http client

Following is my code to handle Multipart using httpclient
if(methodParams.getDataType().length()>0 && methodParams.getDataType().equals("org.springframework.web.multipart.MultipartFile")){
isMultipart = true;
MultipartEntity entity = new MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE );
// For usual String parameters
entity.addPart( methodParams.getVariableDefined(), new StringBody("".toString() , "text/plain", Charset.forName( "UTF-8" )));
postURL.setEntity( entity );
}
but i get the following exception :
Exception in thread "main" java.lang.NoSuchMethodError: org.apache.james.mime4j.util.CharsetUtil.getCharset(Ljava/lang/String;)Ljava/nio/charset/Charset;
at org.apache.http.entity.mime.MIME.<clinit>(MIME.java:51)
at org.apache.http.entity.mime.HttpMultipart.<clinit>(HttpMultipart.java:85)
at org.apache.http.entity.mime.MultipartEntity.<init>(MultipartEntity.java:77)
at org.apache.http.entity.mime.MultipartEntity.<init>(MultipartEntity.java:96)
at com.hexgen.tools.HexgenClassUtils.doPOST(HexgenClassUtils.java:151)
at com.hexgen.reflection.HttpClientRequests.handleHTTPRequest(HttpClientRequests.java:74)
at com.hexgen.reflection.HexgenWebAPITest.main(HexgenWebAPITest.java:115)
EDIT:
following are the dependency i use
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.0.1</version>
</dependency>
how to solve this.
You can take a look at dependencies one more time, perhaps you've missed some jars.
You may also replace your old jars with newer version of a httpclient along with httpmime. httpclient is no longer relying on james mime4j since version 4.1.
You may also end up managing your dependencies with maven. Just in case if you are not using it.
Edit:
You may add the following
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j</artifactId>
<version>0.6</version>
</dependency>

Categories