Using wrk to test a sequence of requests - performance

I'm currently trying to stress-test a web application that allows simple user login, logout and other functionalities with wrk but am really struggling to correctly write a script that allows me to chain multiple requests together.
For example, I'd like to write a script that randomly makes a incoming thread do one of:
1.
login
logout
login
do function A
logout
login
do function B
logout
The application makes use of form-based authentication and maintains sessions. Presently, I can't even figure out how to do a correct post request to my /login route that the application understands such that the wrk thread correctly fills in a username and password to forms in the application. The application works correctly in the browser but I've been really stuck on trying to make this work in a wrk script. Currently I've tried something like:
function request_0 ()
headers = {}
headers["Content-Type"] = "multipart/form-data"
local body = '{"username": "user0", "password": "pass0"}'
return wrk.format("POST", "/login", headers, body)
end
function request_1 ()
headers = {}
headers["Content-Type"] = "multipart/form-data"
local body = '{"username": "user1", "password": "pass1"}'
return wrk.format("POST", "/login", headers, body)
end
requests = {}
requests[0] = request_0
requests[1] = request_1
request = function()
return requests[math.random(0,1)]()
end
To at least simulate multiple possible incoming requests, but my application does not register the username or password given. If anyone could provide help on the proper syntax for the requests, how to chain multiple requests together, and how to handle authentication, this would be really appreciated.

I know next to nothing about Lua, but for chaining + authentication, look to this as a simple example: https://github.com/wg/wrk/blob/master/scripts/auth.lua
Also, for body, try enclosing the JSON in double square braces instead of single quotes...like this:
[[{"key": "value"}]]
For complex scenarios, though, I'd recommend you check out Gatling. Here's a sample: https://www.youtube.com/watch?v=3txt29cG3VM

Related

Read Session Value In .Net Core Web Api [duplicate]

This question already has answers here:
Accessing Session Using ASP.NET Web API
(13 answers)
Closed 3 years ago.
In my Web api when a user login successfully I set session with some values like
HttpContext.Session.SetObject("CurrentUserID", user.Id);
HttpContext.Session.SetObject("CurrentUserRoles",user.Roles);
and just return token and some values to save in cookie
return Ok(new
{
Id = user.Id,
Username = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
Token = tokenString,
role = user.Roles
});
But when the client hit api action which has this line
List<string> userRolesList = HttpContext.Session.GetObject<List<string>>("CurrentUserRoles");
Then always get null value even I have added session inside Startup >Configure
like
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
and ConfigureService also
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds( 60 * 60);
options.Cookie.HttpOnly = true;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
but does work still... Please help.
HTTP is a stateless protocol. Sessions are fake state, enabled by both a server-side and client-side component. The client-side component is a cookie: specifically a Set-Cookie response header. In order for the session to be restored on the next request, the value of this Set-Cookie response header must be sent back via the Cookie request header with each request. A web browser (the client) will do all this automatically, including persisting the cookie locally. However, a thin client like HttpClient, Postman, etc. will not. You would need to independently persist the cookie from the response header and then attach it to each request via the Cookie header in order to maintain the session between requests.
That said, this is a major reason why APIs typically do not, and honestly should not make use of sessions. It's simply a pattern that doesn't make much sense in an API context, and only adds a potential point of failure, since clients must pay attention to the cookie headers, and take manual actions to handle the cookies.

Saml2 Single Logout (SingleLogoutServiceResponseUrl) with Sustainsys and Identity Server 4

I am using Sustainsys Saml2 with Identity Server 4. A customer has asked me if we support support SAML Single Logout.
They have asked for:
Single Logout Request URL
Single Logout Response URL
From what I can see this is probably supported by Sustainsys given the following properties exist.
var idp = new Sustainsys.Saml2.IdentityProvider(new EntityId("https://sso.acme.com"), opt.SPOptions)
{
MetadataLocation = "/metadata/sso-meta.xml",
LoadMetadata = true,
AllowUnsolicitedAuthnResponse = true,
SingleLogoutServiceResponseUrl = "INSERT",
SingleLogoutServiceBinding = Saml2BindingType.HttpRedirect
};
I have two questions:
I can only see one property which matches their request - the SingleLogoutServiceResponseUrl (I don't see a property for the SingleLogoutServiceRequestUrl). How do I configure the Single logout request Url?
How do I determine what the values are for these Url's?
Thanks
Outbound logout requests are sent to the SingleLogoutUrl configured on the Idp. The SingleLogoutResponseUrl is a special one - it's only used when responses should be sent to a different endpoint on the Idp than requests. Normally they are the same and if SingleLogoutResponseUrl is not set, the SingleLogoutUrl is used for both responses and requests.
Ask the Idp people for those.
And as an additional note: You're loading metadata. Then everything should already be in the metadata and you can shorten your code to
var idp = new Sustainsys.Saml2.IdentityProvider(new
EntityId("https://sso.acme.com"), opt.SPOptions)
{
MetadataLocation = "/metadata/sso-meta.xml",
AllowUnsolicitedAuthnResponse = true,
};

How to call web API under specific user permission?

I have a function that allows the end user to execute a Workflow (containing many APIs) or schedule it to run as a background job.
Example: User1 creates Workflow1, which contains 3 APIs (Api1, Api2, Api3), and configures it to run at 9AM every day.
I use HttpClient to call each API like this:
var client = new HttpClient { BaseAddress = new Uri("http://localhost/") };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.PostAsJsonAsync("/api/services/myApp/workflow/Api1?input=something", "").Result;
How do I add the credentials of User1 to the request while the user is not logged in to the application (because it will run automatically as a scheduled job)?
Update 1
I decided to use reflection to call an API by string name.
In the case of executing an API directly, how do I run it under a specific permission?
Update 2
I have put my code inside a using block, but all APIs were fired successfully:
using (_session.Use(1, 3)) // 3 is the Id of User1, who has no permissions
{
// Execute operator
switch (input.Operator.Type)
{
case "api":
executeApiResult = await ExecuteApi(input);
break;
case "procedure":
executeApiResult = await ExecuteProcedure(input);
break;
default:
return new ExecuteOperatorOutput
{
Result = new ExecuteOperatorResult { Status = false, Message = $"Wrong operator type: {input.Operator.Type}" },
WorkflowStatus = false
};
}
}
In the case of executing an API directly, how do I run it under a specific permission?
You can override current session values and call your method inside the using block.
I have put my code inside a using block, but all APIs were fired successfully
Declare your API methods as public virtual as there are some restrictions for AbpAuthorize.
You have two options.
1- You can make those Application Services anonymously accessible. And if you want it to be secure, send an encrypted security token.
2- You didn't mention if your project is MVC or Angular. I assume you have Angular version. You need a bearer token to make authenticated requests. First you have to authenticate user and get a token. Then add this bearer token to every request.
You have to research for using bearer tokens in asp.net core...

Angular2 + Web API + token based authentication

I am trying to learn Angular2
and I am trying to create a simple blog with authentication.
this here is my add a new post method:
[Authorize]
// POST: api/Post
public PostModel Post([FromBody]PostViewModel model)
{
var post = new PostModel
{
Body = model.Body,
Title = model.Title,
AuthorId = IdentityExtensions.GetUserId(User.Identity),
};
var res = blogRepo.AddPost(post);
return res;
}
everything works fine, but IdentityExtension.GetUserId() do not return the most current logged in user but the first user since the app started.
basically I am looking for a way to make sure that the current user logs out on the server as well as on the client (the client side is just a simple removal of the localStorage.removeItem("jwt");)
also there is a good chance that what I am doing is totally wrong, but I can't access the ApplicationUserManager in this controller.
ok I have found the problem, although I haven't managed to solve it yet but I will update this when i do, and I am writing this as an answer since the problem is totally different from what I asked and thought to be.
the problem is related to sending the authentication hints as Thierry Templier suggested. I have a file that exports headers like this:
export const authHeaders = new Headers();
authHeaders.append('Accept', 'application/json');
authHeaders.append('Content-Type', 'application/json');
authHeaders.append('Authorization', 'Bearer ' + localStorage.getItem('jwt'));
And I Import this header where ever I need it. but I am not sure why it always sends a cached value (i.e the first value stored on the client and it has nothing to do with the server side as my question implies).
to solve this issue I just have to make sure the latest access-token stored on localstorage is sent to the server.
EDIT: for now I am constructing the headings in the constructor.

Optemizing basic auth: Save user authentification for follow up requests

I'm using the this tutorial to secure my Web-API calls with basic auth. Basically it checks if there is a auth header on the request and then proves this header against a database:
public static bool CheckPassword(string user, string password)
{
//Do a Database checkup
if(CheckDB(user,password)) {
//if true, set the principal
var identity = new GenericIdentity(user);
SetPrincipal(new GenericPrincipal(identity,null));
}
else {
//return 401...
}
}
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
This is working fine. But it queries the database for every request I do. Even when I just request a JavaScript file.
I like to optimize this process and just call CheckDB() on the first request. All following request should not need another database request. Is it possible to save the Principal? I tried to check Thread.CurrentPrincipal but it seams to reinitialize on every request.
You have a couple of options:
If you have a simple topology with only a single machine handling requests for a relatively small number of users you could implement an in memory cache of usernames and passwords that you can use to efficiently validate subsequent calls. You could implement this using something like ConcurrentDictionary that keys off the username and gives the password, although there are security considerations to such an approach (do you really want passwords to be in memory all the time?).
Set a cookie after a username/password pair has been validated. The cookie could contain something like the timestamp after which the username/password should be revalidated, along with some kind of hash that's generated by a means that only the server knows (and that it can use to validate that it set the timestamp).
With either of these approaches the "CheckPassword" method would either compare the password with the one from the cache, or checking the cookie, and if the result is satisfactory directly create a new principal without calling the database.

Resources