We are trying to build a jmeter testcase which does the following:
login to a system
obtain some information and check whether correct.
Where we are facing issues is because there is a captcha while logging into the system. What we had planned to do was to download the captcha link and display, and wait for user to type in the value. Once done, everything goes as usual.
We couldnt find any plugin that can do the same? Other than writing our own plugin, is there any option here?
I was able to solve it myself. The solution is as follows:
Create a JSR223 PostProcessor (using Groovy)
more practical CAPTCHA example with JSESSIONID handling and proxy setting
using image.flush() to prevent stale CAPTCHA image in dialog box
JSR223 Parameters for proxy connection setting:
Parameters: proxy 10.0.0.1 8080
In it, the following code displays the captcha and waits for user input
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.Icon;
import javax.swing.JOptionPane;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.protocol.http.control.Cookie;
URL urlTemp ;
urlTemp = new URL( "https://your.domainname.com/endpoint/CAPTCHACode");
HttpURLConnection myGetContent = null;
if(args[0]=="proxy" ){
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(args[1], Integer.parseInt(args[2])));
myGetContent = (HttpURLConnection) urlTemp.openConnection(proxy);
}else{
myGetContent = (HttpURLConnection) urlTemp.openConnection();
}
// false for http GET
myGetContent.setDoOutput(false);
myGetContent.connect();
int status = myGetContent.getResponseCode();
log.info("HTTP Status Code: "+Integer.toString(status));
if (status == HttpURLConnection.HTTP_OK) {
//We have 2 Set-Cookie headers in response message but 1 Set-Cookie entry in Map
String[] parts2;
for (Map.Entry<String, List<String>> entries : myGetContent.getHeaderFields().entrySet()) {
if( entries.getKey() == "Set-Cookie" ){
for (String value : entries.getValue()) {
if ( value.contains("JSESSIONID") == true ){
String[] parts = value.split(";",2);
log.info("Response header: "+ entries.getKey() + " - " + parts[0] );
JMeterContext context = JMeterContextService.getContext();
CookieManager manager = context.getCurrentSampler().getCookieManager();
parts2 = parts[0].split("=",2)
Cookie cookie = new Cookie("JSESSIONID",parts2[1],"your.domainname.com","/endpoint",true,0, true, true, 0);
manager.add(cookie);
log.info( cookie.toString() );
log.info("CookieCount "+ manager.getCookieCount().toString() );
}
}
}
}//end of outer for loop
if ( parts2.find() == null ) {
throw new Exception("The Response Header not contain Set-Cookie:JSESSIONID= .");
}
}else{
throw new Exception("The Http Status Code was ${status} , not expected 200 OK.");
}
BufferedInputStream bins = new BufferedInputStream(myGetContent.getInputStream());
String destFile = "number.png";
File f = new File(destFile);
if(f.exists() ) {
boolean fileDeleted = f.delete();
log.info("delete file ... ");
log.info(String.valueOf(fileDeleted));
}
FileOutputStream fout =new FileOutputStream(destFile);
int m = 0;
byte[] bytesIn = new byte[1024];
while ((m = bins.read(bytesIn)) != -1) {
fout.write(bytesIn, 0, m);
}
fout.close();
bins.close();
log.info("File " +destFile +" downloaded successfully");
Image image = Toolkit.getDefaultToolkit().getImage(destFile);
image.flush(); // release the prior cache of Captcha image
Icon icon = new javax.swing.ImageIcon(image);
JOptionPane pane = new JOptionPane("Enter Captcha", 0, 0, null);
String captcha = pane.showInputDialog(null, "Captcha", "Captcha", 0, icon, null, null);
captcha = captcha.trim();
captcha = captcha.replaceAll("\r\n", "");
log.info(captcha);
vars.put("captcha", captcha);
myGetContent.disconnect();
By vars.put method we can use the captcha variable in any way we want. Thank you everyone who tried to help.
Since CAPTHA used to detect non-humans, JMeter will always fail it.
You have to make a workaround in your software: either disable captcha requesting or print somewhere on page correct captcha. Of course, only for JMeter tests.
Dirty workaround? Print the captcha value in alt image for the tests. And then you can retrieve the value and go on.
Related
I am currently using HttpDeclarePushto exploit the Server Push feature in HTTP/2.
I am able to successfully create all the parameters that this function accepts. But the issue is when HttpDeclarePushexecutes it returns a value of 1229 (ERROR_CONNECTION_INVALID) - https://learn.microsoft.com/en-us/windows/desktop/debug/system-error-codes--1000-1299-.
On further investigation I found that the HttpHeaderConnection in _HTTP_HEADER_ID (https://learn.microsoft.com/en-us/windows/desktop/api/http/ne-http-_http_header_id) is actually passed in the function as 'close'. That implies that on every request response the server closes the connection and that is also happening in my case, I checked it in the log.
Here is the code.
class http2_native_module : public CHttpModule
{
public:
REQUEST_NOTIFICATION_STATUS OnBeginRequest(IN IHttpContext * p_http_context, IN IHttpEventProvider * p_provider)
{
HTTP_REQUEST_ID request_id;
const HTTPAPI_VERSION version = HTTPAPI_VERSION_2;
auto pHttpRequest = p_http_context->GetRequest();
auto phttpRequestRaw = pHttpRequest->GetRawHttpRequest();
HANDLE p_req_queue_handle = nullptr;
auto isHttp2 = phttpRequestRaw->Flags;
try {
const auto request_queue_handle = HttpCreateRequestQueue(version, nullptr, nullptr, NULL, &p_req_queue_handle);
const auto verb = phttpRequestRaw->Verb;
const auto http_path = L"/polyfills.0d74a55d0dbab6b8c32c.js"; //ITEM that I want to PUSH to client
const auto query = nullptr;
request_id = phttpRequestRaw->RequestId;
auto headers = phttpRequestRaw->Headers;
auto connId = phttpRequestRaw->ConnectionId;
WriteEventViewerLog(L"OnBeginRequest - Entering HTTPDECLAREPUSH");
headers.KnownHeaders[1].pRawValue = NULL;
headers.KnownHeaders[1].RawValueLength = 0;
const auto is_success = HttpDeclarePush(p_req_queue_handle, request_id, verb, http_path, query, &headers);
sprintf_s(szBuffer, "%lu", is_success);
Log("is_success value", szBuffer); //ERROR CODE 1229 here
HttpCloseRequestQueue(p_req_queue_handle);
}
catch (std::bad_alloc & e)
{
auto something = e;
}
return RQ_NOTIFICATION_CONTINUE;
}
I even tried to update the header connection value as below but it still gives me 1229.
headers.KnownHeaders[1].pRawValue = NULL;
headers.KnownHeaders[1].RawValueLength = 0;
I understand from https://http2.github.io/http2-spec/ that HTTP/2 actually ignores the content in HTTP HEADERs and uses some other mechanism as part of its FRAME.
This brings us to the next question on how we can keep the connection OPEN and is it something related to the FRAME (similar to HEADER) that HTTP2 uses, if so, how C++ or rather Microsoft helps us to play and exploit with the FRAME in HTTP2?
I need to upload a file using an API.
I tried REST CLIENT and didn't find any options.
Tried with HTTP POST and that responded with 415.
Please suggest how to accomplish this
Error 415 is “Unsupported media type”.
You may need to change the media type of the request or check whether that type of file us accepted by the remote server.
https://en.m.wikipedia.org/wiki/List_of_HTTP_status_codes
This solution uses only standard classes of jre 7. Add a step Modified Java Script Value in your transformation. You will have to add two columns in the flow: URL_FORM_POST_MULTIPART_COLUMN and FILE_URL_COLUMN, you can add as many files as you want, you will just have to call outputStreamToRequestBody.write more times.
try
{
//in this step you will need to add two columns from the previous flow -> URL_FORM_POST_MULTIPART_COLUMN, FILE_URL_COLUMN
var serverUrl = new java.net.URL(URL_FORM_POST_MULTIPART_COLUMN);
var boundaryString = "999aaa000zzz09za";
var openBoundary = java.lang.String.format("\n\n--%s\nContent-Disposition: form-data\nContent-Type: text/xml\n\n" , boundaryString);
var closeBoundary = java.lang.String.format("\n\n--%s--\n", boundaryString);
// var netIPSocketAddress = java.net.InetSocketAddress("127.0.0.1", 8888);
// var proxy = java.net.Proxy(java.net.Proxy.Type.HTTP , netIPSocketAddress);
// var urlConnection = serverUrl.openConnection(proxy);
var urlConnection = serverUrl.openConnection();
urlConnection.setDoOutput(true); // Indicate that we want to write to the HTTP request body
urlConnection.setRequestMethod("POST");
//urlConnection.addRequestProperty("Authorization", "Basic " + Authorization);
urlConnection.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
var outputStreamToRequestBody = urlConnection.getOutputStream();
outputStreamToRequestBody.write(openBoundary.getBytes(java.nio.charset.StandardCharsets.UTF_8));
outputStreamToRequestBody.write(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(FILE_URL_COLUMN)));
outputStreamToRequestBody.write(closeBoundary.getBytes(java.nio.charset.StandardCharsets.UTF_8));
outputStreamToRequestBody.flush();
var httpResponseReader = new java.io.BufferedReader(new java.io.InputStreamReader(urlConnection.getInputStream()));
var lineRead = "";
var finalText = "";
while((lineRead = httpResponseReader.readLine()) != null) {
finalText += lineRead;
}
var status = urlConnection.getResponseCode();
var result = finalText;
var time = new Date();
}
catch(e)
{
Alert(e);
}
I solved this by using the solution from http://www.dietz-solutions.com/2017/06/pentaho-data-integration-multi-part.html
Thanks Ben.
He's written a Java class for Multi-part Form submission. I extendd by adding a header for Authorization...
I am working on mvc 4 web application. I want to implement a functionality wherein the scenario is as follows-
There will be gmail id as input for ex: abc#gmail.com. When user will enter this, application should fetch all the calendar events of that respective email id and display them.
I have gone through this-
http://msdn.microsoft.com/en-us/library/live/hh826523.aspx#cal_rest
https://developers.google.com/google-apps/calendar/v2/developers_guide_protocol
I am new to this and i have searched a lot but not got any solution. Please help! Thanks in advance!
Got the solution . Just refer this.
https://github.com/nanovazquez/google-calendar-sample
Please check the steps below.
Add Google Data API SDK.
Try this code.. I wrote this code for one project but I removed some codes that are not related to Google Calender. If you don't want to use SDK, you can simply do http-get or http-post to your calender link based on spec.
CalendarService service = new CalendarService("A.Name");
const string GOOGLE_CALENDAR_FEED = "https://www.google.com/calendar/feeds/";
const string GOOGLE_CALENDAR_DEFAULT_ALL_CALENDAR_FULL = "default/allcalendars/full";
const string GOOGLE_CALENDAR_ALL_PRIVATE_FULL = "private/full";
private void SetUserCredentials() {
var userName = ConfigurationManager.AppSettings["GoogleUserName"];
var passWord = Security.DecryptString(ConfigurationManager.AppSettings["GooglePasswrod"]).ToInsecureString();
if (userName != null && userName.Length > 0) {
service.setUserCredentials(userName, passWord);
}
}
private CalendarFeed GetCalendarsFeed() {
CalendarQuery calendarQuery = new CalendarQuery();
calendarQuery.Uri = new Uri(GOOGLE_CALENDAR_FEED + GOOGLE_CALENDAR_DEFAULT_ALL_CALENDAR_FULL);
CalendarFeed resultFeed = (CalendarFeed)service.Query(calendarQuery);
return resultFeed;
}
private TherapistTimeSlots GetTimeSlots(CalendarEntry entry2) {
string feedstring = entry2.Id.AbsoluteUri.Substring(63);
var postUristring = string.Format("{0}{1}/{2}", GOOGLE_CALENDAR_FEED, feedstring, GOOGLE_CALENDAR_ALL_PRIVATE_FULL);
EventFeed eventFeed = GetEventFeed(postUristring);
slot.Events = new List<Event>();
if (eventFeed != null) {
var orderEventList = (from entity in eventFeed.Entries
from timeslot in ((EventEntry)entity).Times
orderby timeslot.StartTime
select entity).ToList();
}
return slot;
}
private EventFeed GetEventFeed(string postUristring) {
var eventQuery = new EventQuery();
eventQuery.Uri = new Uri(postUristring);
var h = Convert.ToInt32(DateTime.Now.ToString("HH", System.Globalization.DateTimeFormatInfo.InvariantInfo));
eventQuery.StartTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, h, 0, 0);
eventQuery.EndTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, h + 2, 0, 0);
try {
EventFeed eventFeed = service.Query(eventQuery) as EventFeed;
return eventFeed;
}
catch (Exception ex) {
/*
* http://groups.google.com/group/google-calendar-help-dataapi/browse_thread/thread/1c1309d9e6bd9be7
*
* Unfortunately, the calendar API will always issue a redirect to give you a
gsessionid that will optimize your subsequent requests on our servers.
Using the GData client library should be transparent for you as it is taking
care of handling those redirect; but there might some times where this error
occurs as you may have noticed.
The best way to work around this is to catche the Exception and re-send the
request as there is nothing else you can do on your part.
*/
return null;
}
}
I am creating an application that is mentioned to connect to an instance of on owncloud server but i can't find why it doesn't connect to the server .Instead of that the reply i get to the login screen and i get the html code for it
this is the code responsible for the connection
//the network request and reply
QNetworkAccessManager * manager = new QNetworkAccessManager();
QUrl url (url1);
manager->get(QNetworkRequest(url));
connect(manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
SLOT(provideAuthenication(QNetworkReply*,QAuthenticator*)));
connect(manager, SIGNAL(finished(QNetworkReply *)),
this, SLOT(result(QNetworkReply *)));
the reply code
void Login::result(QNetworkReply *reply)
{
reply->deleteLater();
if(reply->error() == QNetworkReply::NoError) {
// Get the http status code
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (v >= 200 && v < 300) // Success
{
qDebug()<<"Here we got the final reply";
QString replyText = reply->readAll();
qDebug()<<replyText;
}
else if (v >= 300 && v < 400) // Redirection
{
qDebug()<<"Get the redirection url";
QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
// Because the redirection url can be relative,
// we have to use the previous one to resolve it
newUrl = reply->url().resolved(newUrl);
QNetworkAccessManager *manager = reply->manager();
QNetworkRequest redirection(newUrl);
QNetworkReply *newReply = manager->get(redirection);
QString replyText = newReply->readAll();
qDebug()<<replyText;
return; // to keep the manager for the next request
}
}
else
{
// Error
qDebug()<<reply->errorString();
}
reply->manager()->deleteLater();
}
could you help me figure out why i get the login screen instead of authentication ?
Try to call connect() before calling manager->get() otherwise when the authentication required signal is triggered, there might not be any slots present to call to handle that signal.
Try this instead:
QNetworkAccessManager * manager = new QNetworkAccessManager();
QUrl url (url1);
connect(manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
SLOT(provideAuthenication(QNetworkReply*,QAuthenticator*)));
connect(manager, SIGNAL(finished(QNetworkReply *)),
this, SLOT(result(QNetworkReply *)));
manager->get(QNetworkRequest(url));
my url # development : http://192.168.0.1:8888/com.company.MyEntryPoint/MyEntrypoint.html
my url # live env : http://www.example.com/com.company.MyEntryPoint/MyEntrypoint.html
I need users to authenticate using open id,
this is how i want my realm to be:
*.company.MyEntryPoint
I wrote a simple code to specify realm:
AuthRequest authReq =
manager.authenticate(
discovered,
returnToUrl,
"*.company.MyEntryPoint"
);
it does not work.
Exception:
org.openid4java.message.MessageException: 0x301: Realm verification failed (2) for: *.company.MyEntryPoint
at org.openid4java.message.AuthRequest.validate(AuthRequest.java:354)
at org.openid4java.message.AuthRequest.createAuthRequest(AuthRequest.java:101)
at org.openid4java.consumer.ConsumerManager.authenticate(ConsumerManager.java:1073)
Of all the combinations I tried, curiously, the following worked:
AuthRequest authReq =
manager.authenticate(
discovered,
returnToUrl,
"http://localhost:8888/com.capgent.MyEntryPoint"
);
This does not solves my issue but rather complicates it :)
According to google and open id spec it should have worked
complete code snippet:
List discoveries = manager.discover(clientUrl);
DiscoveryInformation discovered = manager.associate(discoveries);
AuthRequest authReq = manager.authenticate(discovered, returnToUrl,"*.company.MyEntryPoint");
FetchRequest fetch = FetchRequest.createFetchRequest();
fetch.addAttribute("email", "http://schema.openid.net/contact/email", true);
fetch.addAttribute("country", "http://axschema.org/contact/country/home", true);
fetch.addAttribute("firstname", "http://axschema.org/namePerson/first", true);
fetch.addAttribute("lastname", "http://axschema.org/namePerson/last", true);
fetch.addAttribute("language", "http://axschema.org/pref/language", true);
authReq.addExtension(fetch);
String returnStr;
if (!discovered.isVersion2())
{
returnStr = authReq.getDestinationUrl(true);
}
else
{
returnStr = authReq.getDestinationUrl(false);
}
What am I doing wrong over here ?
returnStr = authReq.getDestinationUrl(false); => returnStr = authReq.getDestinationUrl(true);