I want to verify that session in JBoss 5 is still active and in logged in state. to implement a JWT (json web token).
for this, I need to get session by id.
to debug it: JBoss uses a special version of tomcat called JBoss web.
then I searched "jboss web 2* jar" and added it as source for sources to eclipse then I could debug it. also in eclipse, I have installed from eclipse marketplace FernFlower decompiler (* I took the actual version from https://developer.jboss.org/wiki/VersionOfTomcatInJBossAS)
I referenced those sources
how to refresh JSESSIONID cookie after login
https://github.com/auth0/java-jwt
my solution may help other pseudo tomcat serverlet servers
package com.mysoftware.controller.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.mysoftware.util.SqlInjectionAndXSSRequestWrapper;
import com.mysoftware.model.User;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.jboss.seam.security.Identity;
import org.jboss.seam.web.ServletContexts;
import org.jboss.util.Base64;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Cipher;
public class JWTAuthorization {
public static String isSessionIdLoggedIn(String requestedSessionId) {
try {
// get the request
HttpServletRequest request =ServletContexts.instance().getRequest();
ServletRequest serverletRequest = ((ServletRequestWrapper)request).getRequest();
// first need to unwrap the request until the core - org.apache.catalina.connector.Request.
// i had additional wrapper around the request SqlInjectionAndXSSRequestWrapper. (you probably wont have it)
// for simplicity i added SqlInjectionAndXSSRequestWrapper.request to my class, just saved the constructor argument.
SqlInjectionAndXSSRequestWrapper injectionRequest = (SqlInjectionAndXSSRequestWrapper) serverletRequest;
// code may start here, I run it and cast it and debug it and when I see it crash: "can't convert class x to y'. I understand which class it is and unwrap it accordingly.
RequestFacade requestFacade = (RequestFacade) injectionRequest.request;
Field catalinaRequestField;
//Getting actual catalina request using reflection
catalinaRequestField = requestFacade.getClass().getDeclaredField( "request" );
catalinaRequestField.setAccessible( true ); // grant access to (protected) field
Request realRequest = (Request)catalinaRequestField.get( requestFacade );
Manager manager = realRequest.getContext().getManager();
HttpSession session = null;
try {
session=(HttpSession) manager.findSession(requestedSessionId);
} catch (IOException var7) {}
if (session != null && !((Session) session).isValid()) {session = null;}
if (session != null) {((Session) session).access();} // mark usage
if (session != null && session.isNew()) return "new";
if (session != null )
{
Identity identity = (Identity)session.getAttribute("org.jboss.seam.security.identity");
if (identity != null && identity.isLoggedIn()) return "login";
}
return "not login";
} catch (Exception e1) {
e1.printStackTrace();
return "exception";
}
}
protected final static String sessionidencryptionkey="1234567890ghdg";
protected final static String jwtsecret="1234567890sdghsg";
public static String getTokenForCRM(User user)
{
try {
Algorithm algorithm = Algorithm.HMAC256(jwtsecret);
String token = JWT.create()
.withSubject(user.getId().toString())
.withArrayClaim("CRM", new String[]{ user.getAccount().getCrm() } )
.withClaim("SessionID", encrypt( ServletContexts.instance().getRequest().getSession().getId() , sessionidencryptionkey) )
.sign(algorithm);
return token;
} catch (Exception exception){
//Invalid Signing configuration / Couldn't convert Claims.
}
return "ERROR_CREATEING_TOKEN";
}
public static String getSessionId(DecodedJWT token)
{
try {
return decrypt( token.getClaim("SessionID").asString() , sessionidencryptionkey) ;
} catch (Exception e) {
//e.printStackTrace();
return null;
}
}
public static DecodedJWT verifyToken(String token)
{
try {
Algorithm algorithm = Algorithm.HMAC256(jwtsecret);
JWTVerifier verifier = JWT.require(algorithm)
//.withIssuer("auth0")
.build(); //Reusable verifier instance
DecodedJWT jwt = verifier.verify(token);
return jwt;
} catch (JWTVerificationException exception){
//Invalid signature/claims
}
return null;
}
public static String encrypt(String strClearText,String strKey) throws Exception{
String strData="";
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
byte[] encrypted=cipher.doFinal(strClearText.getBytes());
strData=new String(encrypted);
//strData=Base64.encodeBytes(encrypted);
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e);
}
return strData;
}
public static String decrypt(String strEncrypted,String strKey) throws Exception{
String strData="";
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
final byte[] strEncryptedBytes=strEncrypted.getBytes();
// final byte[] strEncryptedBytes==Base64.encode(strEncrypted)
byte[] decrypted=cipher.doFinal(strEncryptedBytes);
strData=new String(decrypted);
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e);
}
return strData;
}
}
my testing code was.
inside a controller i had:
call it without wuery on different browsers,
then add parameter of the other session id in one of the browsers
#GET
#Path("testJWTSessionCheck")
#Produces("application/json")
public String testJWTSessionCheck( #QueryParam("s") String requestedSessionId) {
if(requestedSessionId!=null && requestedSessionId.length()>5) {
JWTAuthorization.isSessionIdLoggedIn(requestedSessionId);
}
HttpSession session1 = ServletContexts.instance().getRequest().getSession(false);
return session1.getId();
}
Related
I know that request template supports XPath, so that I can get value from request like {{xPath request.body '/outer/inner/text()'}}. I already have a XML file as response, and I want to inject this value I got from request, but keep the other parts of this response XML intact. For example, I want to inject it to XPATH /svc_result/slia/pos/msid.
And I need to use it in standalone mode.
I see another question(Wiremock Stand alone - How to manipulate response with request data) but that was with JSON, I have XML request/response.
How can it be done? Thanks.
For example, I have this definition of mapping:
{
"request": {
"method": "POST",
"bodyPatterns": [
{
"matchesXPath": {
"expression": "/svc_init/slir/msids/msid[#type='MSISDN']/text()",
"equalTo": "200853000105614"
}
},
{
"matchesXPath": "/svc_init/hdr/client[id and pwd]"
}
]
},
"response": {
"status": 200,
"bodyFileName": "slia.xml",
"headers": {
"Content-Type": "application/xml;charset=UTF-8"
}
}
}
And this request:
<?xml version="1.0"?>
<!DOCTYPE svc_init>
<svc_init ver="3.2.0">
<hdr ver="3.2.0">
<client>
<id>dummy</id>
<pwd>dummy</pwd>
</client>
</hdr>
<slir ver="3.2.0" res_type="SYNC">
<msids>
<msid type="MSISDN">200853000105614</msid>
</msids>
</slir>
</svc_init>
I expect this response, with xxxxxxxxxxx replaced with the <msid> in the request.
<?xml version="1.0" ?>
<!DOCTYPE svc_result SYSTEM "MLP_SVC_RESULT_320.DTD">
<svc_result ver="3.2.0">
<slia ver="3.0.0">
<pos>
<msid type="MSISDN" enc="ASC">xxxxxxxxxxx</msid>
<pd>
<time utc_off="+0800">20111122144915</time>
<shape>
<EllipticalArea srsName="www.epsg.org#4326">
<coord>
<X>00 01 01N</X>
<Y>016 31 53E</Y>
</coord>
<angle>0</angle>
<semiMajor>2091</semiMajor>
<semiMinor>2091</semiMinor>
<angularUnit>Degrees</angularUnit>
</EllipticalArea>
</shape>
<lev_conf>90</lev_conf>
</pd>
<gsm_net_param>
<cgi>
<mcc>100</mcc>
<mnc>01</mnc>
<lac>2222</lac>
<cellid>10002</cellid>
</cgi>
<neid>
<vmscid>
<vmscno>00004946000</vmscno>
</vmscid>
<vlrid>
<vlrno>99994946000</vlrno>
</vlrid>
</neid>
</gsm_net_param>
</pos>
</slia>
</svc_result>
My first thought was to use transformerParameters to change the response file by inserting the value from the body. Unfortunately, WireMock doesn't resolve the helpers before inserting them into the body response. So while we can reference that MSID value via an xpath helper like
{{xPath request.body '/svc_init/slir/msids/msid/text()'}}
if we try to insert that as a custom transformer parameter, it won't resolve. (I've written up an issue on the WireMock github about this.)
Unfortunately, I think this leaves us with having to write a custom extension that will take the request and find the value and then modify the response file. More information on creating a custom transformer extensions can be found here.
At last I created my own transformer:
package com.company.department.app.extensions;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
public class NLGResponseTransformer extends ResponseTransformer {
private static final Logger LOG = LoggerFactory.getLogger(NLGResponseTransformer.class);
private static final String SLIA_FILE = "/stubs/__files/slia.xml";
private static final String REQ_IMSI_XPATH = "/svc_init/slir/msids/msid";
private static final String[] RES_IMSI_XPATHS = {
"/svc_result/slia/pos/msid",
"/svc_result/slia/company_mlp320_slia/company_netinfo/company_ms_netinfo/msid"
};
private static final String[] RES_TIME_XPATHS = {
// for slia.xml
"/svc_result/slia/company_mlp320_slia/company_netinfo/company_ms_netinfo/time",
// for slia_poserror.xml
"/svc_result/slia/pos/poserror/time"
};
private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
private static final String UTC_OFF = "utc_off";
private static final String TRANSFORM_FACTORY_ATTRIBUTE_INDENT_NUMBER = "indent-number";
protected static final String COMPANY_MLP_320_SLIA_EXTENSION_DTD = "company_mlp320_slia_extension.dtd";
protected static final String MLP_SVC_RESULT_320_DTD = "MLP_SVC_RESULT_320.DTD";
#Override
public String getName() {
return "inject-request-values";
}
#Override
public Response transform(Request request, Response response, FileSource fileSource, Parameters parameters) {
Document responseDocument = injectValuesFromRequest(request);
String transformedResponse = transformToString(responseDocument);
if (transformedResponse == null) {
return response;
}
return Response.Builder.like(response)
.but()
.body(transformedResponse)
.build();
}
private Document injectValuesFromRequest(Request request) {
// NOTE: according to quickscan:
// "time" element in the MLP is the time MME reports cell_id to GMLC (NLG), NOT the time when MME got the cell_id.
LocalDateTime now = LocalDateTime.now();
Document responseTemplate = readDocument(SLIA_FILE);
Document requestDocument = readDocumentFromBytes(request.getBody());
if (responseTemplate == null || requestDocument == null) {
return null;
}
try {
injectIMSI(responseTemplate, requestDocument);
injectTime(responseTemplate, now);
} catch (XPathExpressionException e) {
LOG.error("Cannot parse XPath expression {}. Cause: ", REQ_IMSI_XPATH, e);
}
return responseTemplate;
}
private Document readDocument(String inputStreamPath) {
try {
DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
// ignore missing dtd
builder.setEntityResolver((publicId, systemId) -> {
if (systemId.contains(COMPANY_MLP_320_SLIA_EXTENSION_DTD) ||
systemId.contains(MLP_SVC_RESULT_320_DTD)) {
return new InputSource(new StringReader(""));
} else {
return null;
}
});
return builder.parse(this.getClass().getResourceAsStream(inputStreamPath));
} catch (Exception e) {
LOG.error("Cannot construct document from resource path. ", e);
return null;
}
}
private Document readDocumentFromBytes(byte[] array) {
try {
DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
// ignore missing dtd
builder.setEntityResolver((publicId, systemId) -> {
if (systemId.contains(COMPANY_MLP_320_SLIA_EXTENSION_DTD) ||
systemId.contains(MLP_SVC_RESULT_320_DTD)) {
return new InputSource(new StringReader(""));
} else {
return null;
}
});
return builder.parse(new ByteArrayInputStream(array));
} catch (Exception e) {
LOG.error("Cannot construct document from byte array. ", e);
return null;
}
}
private XPath newXPath() {
return XPathFactory.newInstance().newXPath();
}
private void injectTime(Document responseTemplate, LocalDateTime now) throws XPathExpressionException {
for (String timeXPath: RES_TIME_XPATHS) {
Node timeTarget = (Node) (newXPath().evaluate(timeXPath, responseTemplate, XPathConstants.NODE));
if (timeTarget != null) {
// set offset in attribute
Node offset = timeTarget.getAttributes().getNamedItem(UTC_OFF);
offset.setNodeValue(getOffsetString());
// set value
timeTarget.setTextContent(TIME_FORMAT.format(now));
}
}
}
private void injectIMSI(Document responseTemplate, Document requestDocument) throws XPathExpressionException {
Node imsiSource = (Node) (newXPath().evaluate(REQ_IMSI_XPATH, requestDocument, XPathConstants.NODE));
String imsi = imsiSource.getTextContent();
for (String xpath : RES_IMSI_XPATHS) {
Node imsiTarget = (Node) (newXPath().evaluate(xpath, responseTemplate, XPathConstants.NODE));
if (imsiTarget != null) {
imsiTarget.setTextContent(imsi);
}
}
}
private String transformToString(Document document) {
if (document == null) {
return null;
}
document.setXmlStandalone(true); // make document to be standalone, so we can avoid outputing standalone="no" in first line
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans;
try {
trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "no"); // no extra indent; file already has intent of 4
// cannot find a workaround to inject dtd in doctype line. TODO
//trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "MLP_SVC_RESULT_320.DTD [<!ENTITY % extension SYSTEM \"company_mlp320_slia_extension.dtd\"> %extension;]");
StringWriter sw = new StringWriter();
trans.transform(new DOMSource(document), new StreamResult(sw));
// Spaces between tags are considered as text node, so when outputing we need to remove the extra empty lines
return sw.toString().replaceAll("\\n\\s*\\n", "\n");
} catch (TransformerException e) {
LOG.error("Cannot transform response document to String. ", e);
return null;
}
}
/**
* Compare system default timezone with UTC and get zone offset in form of (+/-)XXXX.
* Dependent on the machine default timezone/locale.
* #return
*/
private String getOffsetString() {
// getting offset in (+/-)XX:XX format, or "Z" if is UTC
String offset = ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()).getOffset().toString();
if (offset.equals("Z")) {
return "+0000";
}
return offset.replace(":", "");
}
}
And use it like this:
mvn package it as a JAR(non-runnable), put it aside wiremock standalone jar, for example libs
Run this:
java -cp libs/* com.github.tomakehurst.wiremock.standalone.WireMockServerRunner --extensions com.company.department.app.extensions NLGResponseTransformer --https-port 8443 --verbose
Put the whole command on the same line.
Notice the app jar which contains this transformer and wiremock standalone jar should be among classpath. Also, other dependencies under libs are needed. (I use jib maven plugin which copies all dependencies under libs/; I also move app and wiremock jars to libs/, so I can put "-cp libs/*"). If that does not work, try to specify the location of these two jars in -cp. Be ware that Wiremock will runs OK even when the extension class is not found. So maybe add some loggings.
You can use --root-dir to point to stubs files root, for example --root-dir resources/stubs in my case. By default it points to .(where java runs).
I am trying to set up Dead Letter Queue monitoring for a system. So far, I can get it to be thrown in the DLQ queue without problems when the message consumption fails on the consumer. Now I'm having some trouble with getting the reason why it failed;
currently I get the following
java.lang.Throwable: Delivery[2] exceeds redelivery policy imit:RedeliveryPolicy
{destination = queue://*,
collisionAvoidanceFactor = 0.15,
maximumRedeliveries = 1,
maximumRedeliveryDelay = -1,
initialRedeliveryDelay = 10000,
useCollisionAvoidance = false,
useExponentialBackOff = true,
backOffMultiplier = 5.0,
redeliveryDelay = 10000,
preDispatchCheck = true},
cause:null
I do not know why cause is coming back as null. I'm using Spring with ActiveMQ. I'm using the DefaultJmsListenerContainerFactory, which creates a DefaultMessageListenerContainer. I would like cause to be filled with the exception that happened on my consumer but I can't get it to work. Apparently there's something on Spring that's not bubbling up the exception correctly, but I'm not sure what it is. I'm using spring-jms:4.3.10. I would really appreciate the help.
I am using spring-boot-starter-activemq:2.2.2.RELEASE (spring-jms:5.2.2, activemq-client-5.15.11) and I have the same behavior.
(links point to the versions I use)
The rollback cause is added here for the POSION_ACK_TYPE (sic!).
Its assignment to the MessageDispatch is only happening in one place: when dealing with a RuntimeException in the case there is a javax.jms.MessageListener registered.
Unfortunately (for this particular case), Spring doesn't register one, because it prefers to deal with its own hierarchy. So, long story short, there is no chance to make it happen with Spring out-of-the-box.
However, I managed to write an hack-ish way of getting an access to the MessageDispatch instance dealt with, inject the exception as the rollback cause, and it works!
package com.example;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import javax.jms.*;
public class MyJmsMessageListenerContainer extends DefaultMessageListenerContainer {
private final MessageDeliveryFailureCauseEnricher messageDeliveryFailureCauseEnricher = new MessageDeliveryFailureCauseEnricher();
private MessageConsumer messageConsumer; // Keep for later introspection
#Override
protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
this.messageConsumer = super.createConsumer(session, destination);
return this.messageConsumer;
}
#Override
protected void invokeListener(Session session, Message message) throws JMSException {
try {
super.invokeListener(session, message);
} catch (Throwable throwable) {
messageDeliveryFailureCauseEnricher.enrich(throwable, this.messageConsumer);
throw throwable;
}
}
}
Note: don't deal with the Throwable by overriding the protected void handleListenerException(Throwable ex) method, because at that moment some cleanup already happened in the ActiveMQMessageConsumer instance.
package com.example;
import org.apache.activemq.ActiveMQMessageConsumer;
import org.apache.activemq.command.MessageDispatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import javax.jms.MessageConsumer;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
class MessageDeliveryFailureCauseEnricher {
private static final Logger logger = LoggerFactory.getLogger(MessageDeliveryFailureCauseEnricher.class);
private final Map<Class<?>, Field> accessorFields = new HashMap<>();
private final Field targetField;
public MessageDeliveryFailureCauseEnricher() {
this.targetField = register(ActiveMQMessageConsumer.class, "deliveredMessages");
// Your mileage may vary; here is mine:
register("brave.jms.TracingMessageConsumer", "delegate");
register("org.springframework.jms.connection.CachedMessageConsumer", "target");
}
private Field register(String className, String fieldName) {
Field result = null;
if (className == null) {
logger.warn("Can't register a field from a missing class name");
} else {
try {
Class<?> clazz = Class.forName(className);
result = register(clazz, fieldName);
} catch (ClassNotFoundException e) {
logger.warn("Class not found on classpath: {}", className);
}
}
return result;
}
private Field register(Class<?> clazz, String fieldName) {
Field result = null;
if (fieldName == null) {
logger.warn("Can't register a missing class field name");
} else {
Field field = ReflectionUtils.findField(clazz, fieldName);
if (field != null) {
ReflectionUtils.makeAccessible(field);
accessorFields.put(clazz, field);
}
result = field;
}
return result;
}
void enrich(Throwable throwable, MessageConsumer messageConsumer) {
if (throwable != null) {
if (messageConsumer == null) {
logger.error("Can't enrich the MessageDispatch with rollback cause '{}' if no MessageConsumer is provided", throwable.getMessage());
} else {
LinkedList<MessageDispatch> deliveredMessages = lookupFrom(messageConsumer);
if (deliveredMessages != null && !deliveredMessages.isEmpty()) {
deliveredMessages.getLast().setRollbackCause(throwable); // Might cause problems if we prefetch more than 1 message
}
}
}
}
private LinkedList<MessageDispatch> lookupFrom(Object object) {
LinkedList<MessageDispatch> result = null;
if (object != null) {
Field field = accessorFields.get(object.getClass());
if (field != null) {
Object fieldValue = ReflectionUtils.getField(field, object);
if (fieldValue != null) {
if (targetField == field) {
result = (LinkedList<MessageDispatch>) fieldValue;
} else {
result = lookupFrom(fieldValue);
}
}
}
}
return result;
}
}
The magic happen in the second class:
At construction time we make some private fields accessible.
When a Throwable is caught, we traverse these fields to end up with the appropriate MessageDispatch instance (beware if you prefetch more than 1 message), and inject it the throwable we want to be part of the dlqDeliveryFailureCause JMS property.
I crafted this solution this afternoon, after hours of debugging (thanks OSS!) and many trials and errors. It works, but I have the feeling it's more of an hack than a real, solid solution.
With that in mind, I made my best to avoid side effects, so the worst that can happen is no trace of the original Throwable in the message ending in the Dead Letter Queue.
If I missed the point somewhere, I'b be glad to learn more about this.
I wrote code in our Spring Boot 2 application to make a third-party API call with HTTPUrlConnection.
public String loginApi(LoginDTO loginDto)
{
String responseData = null;
HttpURLConnection conn = null;
try {
link = authBaseUrl + loginUrl;
url = new URL(link);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty(CONTENT_TYPE, MEDIA_TYPE);
String body = getAuth0LoginDto(loginDto);
// =====================
// For POST only - START
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(body.getBytes(StandardCharsets.UTF_8));
os.flush();
os.close();
// For POST only - END
// ====================
try (BufferedReader br = (conn.getResponseCode() >= 400
? new BufferedReader(new InputStreamReader(conn.getErrorStream()))
: new BufferedReader(new InputStreamReader(conn.getInputStream())))) {
StringBuilder everything = new StringBuilder();
String output = null;
while ((output = br.readLine()) != null) {
everything.append(output);
}
responseData = everything.toString();
}
} catch (JsonProcessingException e) {
throw new Auth0Exception("Could not create Auth0 Login Body", e);
} catch (IOException e) {
throw new Auth0Exception("Error with Login API", e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
return responseData;
}
Now, I am very much used to doing real integration testing, where I make a real call to the web-service and check the results.
I am now being asked to use strictly Mockito, not PowerMockito, not EasyMock, to create mocking tests, and I have never done that before. My knowledge of Mockito is weak also since I haven't used it in a very long time.
So, I know it has been asked before, and I have really searched on the internet, and I really haven't found a full piece of code as an example. I see code snippets which leaves me with pieces missing, and I am not knowledgeable enough to add those parts myself.
I know this code actual implementation works fine, and the integration test works fine also. But, what I have seen before is that some users are being told they need to change their client code in order to make the mockito tests work.
If I don't get the mocking tests working for HTTPUrlConnection, then I'll be forced to switch over to RestTemplate and Mocking since my co-worker insists we use RestTemplate anyway.
Thanks!
Since you have asked for a small example which does not make sense but should show the idea:
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class App {
public int status(URL url) {
HttpURLConnection urlConnection = null;
try {
urlConnection = create(url);
return urlConnection.getResponseCode();
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}
HttpURLConnection create(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
}
I would implement this with a spy and as I recommended a mocked HttpURLConnection:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
#ExtendWith(MockitoExtension.class)
class AppTest {
#Spy
App app;
#Mock
HttpURLConnection connection;
#Test
void status() throws IOException {
int expected = 200;
doReturn(connection).when(app).create(any());
doReturn(expected).when(connection).getResponseCode();
URL url = new URL("http://www.google.ats");
int status = app.status(url);
Assertions.assertEquals(expected, status);
}
}
Maybe somebody can help me find out how to solve this.
I am using jersey-apache-client 1.17
I tried to use Jersey client to build a standalone application (no Servlet container or whatever, just the Java classes) which communicates with a RESTFUL API, and everything worked fine until I tried to handle the mediatype "text/csv; charset=utf-8" which is a CSV stream sent by the server.
The thing is that I can read this stream with the following code:
InputStreamReader reader = new InputStreamReader(itemExportBuilder
.get(ClientResponse.class).getEntityInputStream());
Csv csv = new Csv();
Input input = csv.createInput(reader);
try {
String[] readLine;
while ((readLine = input.readLine()) != null) {
LOG.debug("Reading CSV: {}", readLine);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
But I'd like to encapsulate it and put it into a MessageBodyReader. But after writing this code, I just can't make the client use the following class:
package client.response;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Provider
public class ItemExportMessageBodyReader implements MessageBodyReader<ItemExportResponse> {
private static final Logger LOG = LoggerFactory.getLogger(ItemExportMessageBodyReader.class);
private static final Integer SKU = 0;
private static final Integer BASE_SKU = 1;
public boolean isReadable(Class<?> paramClass, Type type, Annotation[] annotations,
MediaType mediaType) {
LOG.info("Cheking if content is readable or not");
return paramClass == ItemExportResponse.class && !mediaType.isWildcardType()
&& !mediaType.isWildcardSubtype()
&& mediaType.isCompatible(MediaType.valueOf("text/csv; charset=utf-8"));
}
public ItemExportResponse readFrom(Class<ItemExportResponse> paramClass, Type paramType,
Annotation[] paramArrayOfAnnotation, MediaType paramMediaType,
MultivaluedMap<String, String> paramMultivaluedMap, InputStream entityStream)
throws IOException, WebApplicationException {
InputStreamReader reader = new InputStreamReader(entityStream);
Csv csv = new Csv();
Input input = csv.createInput(reader);
List<Item> items = new ArrayList<Item>();
try {
String[] readLine;
while ((readLine = input.readLine()) != null) {
LOG.trace("Reading CSV: {}", readLine);
Item item = new Item();
item.setBaseSku(readLine[BASE_SKU]);
items.add(item);
}
} catch (IOException e) {
LOG.warn("Item export HTTP response handling failed", e);
} finally {
try {
input.close();
} catch (IOException e) {
LOG.warn("Could not close the HTTP response stream", e);
}
}
ItemExportResponse response = new ItemExportResponse();
response.setItems(items);
return response;
}
}
The following documentation says that the preferred way of making this work in a JAX-RS client to register the message body reader with the code below:
Using Entity Providers with JAX-RS Client API
Client client = ClientBuilder.newBuilder().register(MyBeanMessageBodyReader.class).build();
Response response = client.target("http://example/comm/resource").request(MediaType.APPLICATION_XML).get();
System.out.println(response.getStatus());
MyBean myBean = response.readEntity(MyBean.class);
System.out.println(myBean);
Now the thing is that I can't use the ClientBuilder. I have to extend from a specific class which constructs the client another way, and I have no access to change the construction.
So when I receive the response from the server, the client fails with the following Exception:
com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class client.response.ItemExportResponse, and Java type class client.response.ItemExportResponse, and MIME media type text/csv; charset=utf-8 was not found
Any other way to register my MessageBodyReader?
OK. If anybody would bump into my question I solved this mystery by upgrading from Jersey 1.17 to version 2.9. The documentation I linked above also covers this version not the old one, this is where the confusion stems from.
Jersey introduced backward INCOMPATIBLE changes starting from version 2, so I have no clue how to configure it in version 1.17.
In version 2 the proposed solution worked fine.
Hi Iam Fresher in Jmeter
I have wrote one Java Sampler code. I don't know that is correct or wrong. If I put that URL and parameter in Http Request getting proper result, but if written as a javasampler i didn't get that result, Iam getting Pass result but no response and request data
My Sampler code is:
package org.apache.jmeter.protocol.java.test;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
public class ExampleJavaSampler extends AbstractJavaSamplerClient implements Serializable {
String mySvc = "";
JavaSamplerContext context;
public Arguments getDefaultParameters(){
Arguments arg = new Arguments();
arg.addArgument("url", "http://www.url.com:5252/Switch/Download");
arg.addArgument("e_type", "bank");
arg.addArgument("e_id", "4");
arg.addArgument("b_id", "1");
arg.addArgument("a_id", "0002");
arg.addArgument("link_branch", "");
arg.addArgument("terminal_id", "");
arg.addArgument("version", "10");
arg.addArgument("entity", "100");
System.out.println("inside default");
return arg;
}
public void setupTest(JavaSamplerContext context) {
System.out.println("inside Setup");
}
public SampleResult runTest(JavaSamplerContext context) {
System.out.println("Inside Run test:");
String urls = context.getParameter("url");
String e_type = context.getParameter("e_type");
String e_id = context.getParameter("e_id");
String b_id = context.getParameter("b_id");
String a_id = context.getParameter("a_id");
String l_branch = context.getParameter("e_type");
String t_id = context.getParameter("e_type");
String oion = context.getParameter("e_type");
String entity = context.getParameter("e");
SampleResult result = new SampleResult();
result.getURL();
result.setSampleLabel("Test Result");
result.setDataType(SampleResult.TEXT);
result.sampleStart();
try{
java.net.URL url = new java.net.URL(urls+"?=e_type="+e_type+"&e_id="+e_id+"&b_id="+b_id);
System.out.println(url);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection)url.openConnection(); // have to cast connection
connection.setRequestMethod("POST");
connection.connect();
result.sampleEnd(); // stop stopwatch
result.setSuccessful( true );
result.setResponseMessage( "Successfully performed action" );
result.setResponseCodeOK(); // 200 code
} catch (Exception e) {
result.sampleEnd(); // stop stopwatch
result.setSuccessful( false );
result.setResponseMessage( "Exception: " + e );
// get stack trace as a String to return as document data
java.io.StringWriter stringWriter = new java.io.StringWriter();
e.printStackTrace( new java.io.PrintWriter( stringWriter ) );
result.setResponseData( stringWriter.toString() );
result.setDataType( org.apache.jmeter.samplers.SampleResult.TEXT );
result.setResponseCode( "500" );
}
return result;
}
void teardownTest() {
System.out.println("inside tear Down:");
}
}
After this code I made .jar file and put lib/ext. Then I called in Javarequest and all parameters are diplayed there, then I run this Test plan, getting success message nut no result
This is the right way or we have to add some thing for there for result?
I've already responded here.
You need to call result.setResponseData() inside your try block elsewise you won't see anything on success. "Response Data" piece of "View Results Tree" listener is populated only on error according to your code.