Visual studio Web Performance tests - OAuth 2.0 - c#

I am trying to create the Web Performance tests for an app that is using Identity Server 3. I can't figure out how to simulate login and get token.
For example, I am using myapp.com and identity server is hosted on identity.com. All my endpoints in myapp.com/api are secured and require Bearer token.
identity.com can provide me token in exchange for a username and password. identity.com will redirect me to a myapp.com/tokenRedirect?token=***. How can I catch the token and use it as an Authorization header for API requests?
There are some solutions for JMeter but could not find any for VS 2017 tests.

Redirections are handled automatically, by default, in a test recorded by Visual Studio and hence the redirection response containing the token is not accessible. Setting the FollowRedirects property of the request to False allows the response containing the redirection to be accessed by the usual extraction rules and/or plugins etc. One of them can be used to find the token value and save it to a context parameter (CP). Having turned off the automatic redirection handling, a new request should be added (use the Insert request command, do not use Add dependent request) and it should have the request that the redirection wants. Hence its url should be of the form myapp.com/tokenRedirect?token={{TheCPWithTheToken}}.
In later requests the CP with the token can be added via the Add header command, or an existing header field can be modified to use the CP.

Related

DocuSign C# API - USER_LACKS_MEMBERSHIP error for every token-authenticated request

We had a working application, we went through the go-live process, and everything was running live for several days. Then we started getting SSL errors, and we saw that the nuget package for the DocuSign package had an update (I believe this was all for the 11/13/2019 2019 certificates auto-update), so we updated our code, but now every request returns the USER_LACKS_MEMBERSHIP error for every token-authenticated request.
Things I can confirm are not the issue:
We have authenticated the app via account.docusign.com and the oauth signature impersonation scope, and the testing and live paths are in the API approved Redirect URIs.
We have the correct base path in the configuration (https://na3.docusign.net, as shown on our Apps and Keys page)
The base path did not change after we get the token back (The BaseUri on the Account object matches what we started with)
We are using the correct user for the configuration (The value labeled "API Username" in the Apps and Keys page is entered as "IMPERSONATED_USER_GUID" in appsettings.json and successfully used in creating the token as parameter UserID, which also matches our user account's ID shown in the backend, so we are not confusing it with TARGET_ACCOUNT_ID or CLIENT_ID, and shuffling those around causes errors much earlier at the token generation step).
We only have one user: the administrator of the DocuSign account. Their ID appears in the API configuration labeled as "API Username". The DocuSign administration backend doesn't display a membership tab anywhere for us to correct any possible issues with a user lacking membership. As far as I can tell, Membership is a higher tier account option than what we're paying for, so I'm confused how we could be having problems with a feature we haven't bought.
We get this error for checking envelope status. We get this error for trying to create new envelopes. We get this error for trying to get Account information. The only thing we can do is get an authentication token, but then that token can't be used to make any further authenticated requests.
Is there anything I'm missing that could be causing this other than some database error on DocuSign that I can't correct through the tools available to me? The package update changed the order of which class constructor accepts the ApiClient object, and there's a new AccessToken field on the Configuration class (which I filled out, but doesn't seem to have any effect, since we're still adding the Authorization/Bearer header manually). I'm out of ideas on what to try next.
Are you using the production environment or the demo environment?
I suspect that what's happening is that you are getting them mixed. As the baseUrl should not be demo.docusign.net etc. if you're using production (as indicated by your na3.docusign.net address) but you must ensure that the same account/user from production is also used.
So, the 4 things to check:
userId
accountId.
baseURI
authURI (account-d.docusign.com vs. account.docusign.com)
All of these should match and be for the same account in the same env.

How can I validate MSAL token on API Management?

I have a desktop app which uses ADAL for authentication, this app make requests to an API on the API Management azure service. After migrating the code to use MSAL, the API Management returns 401 saying that my token is invalid. The only difference that I see spying the requests is that ADAL makes a request to this endpoint /tenantID/oauth2/token and MSAL /tenantID/oauth2/v2.0/token.
In my API Management I have this policy:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid. AAD" require-expiration-time="false">
<openid-config url="https://login.microsoftonline.com/tenantID/.well-known/openid-configuration" />
</validate-jwt>
I tried to change the well known url to v2.0 endpoint but get the same error. How can I validate the token using MSAL?
From the Note in the doc, when changing the well known url to v2.0, you may need to use common instead of tenantID.
<openid-config url="https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration" />
Also, make sure you have done the step 10 in this link correctly:
If you use v2 endpoints, use the scope you created for the backend-app
in the Default scope field. Also, make sure to set the value for
the accessTokenAcceptedVersion property to 2 in your
application manifest.

How to validate oauth token in my application using load balancer?

I have an api project configured with oauth for authentication. since the application uses load balancer to manage multiple requests, let's assume (server-1 ad server-2).
first request with valid credentials => server 1 (here token was generated)
second request with token included in header => server 2
now second request getting "Authorization Denied". How to handle this scenario?
Guess you are looking for something like vouch-proxy.
Here some useful links:
Article: https://medium.com/lasso/use-nginx-and-lasso-to-add-google-authentication-to-any-application-d3a8a7f073dd
Project: https://github.com/vouch/vouch-proxy

Ways to secure an anonymous Web API request

I have a ASP.NET MVC (NOT ASP.NET Core) single page application with angular js on the front end.
My client (browser) talks to server through ASP.NET Web APIs. Now, the web application is on https but anonymous. There is no login/ user authentication.
The web app is in the form of a wizard where user can go back and forth and add or update input fields on the web page. The form input values are then updated on the server through Web API.
I'm looking for a way to secure my Web API calls alone, especially the POST/ PUT requests. In summary, I want to prevent any user calling my Web API directly from POSTMAN or Fiddler. The Web API, though anonymous can be only called from the browser session where the request originated.
What are options do I have to achieve this?
Can I use Anti-Forgery token here (without authentication)?
One way, I can think of achieving this is to add a custom header to each request and store some kind of session key in the header. Then, validate the custom header on every request I received from client. Are any other ways of achieving this out-of-box or some proven library without going for custom solution?
If I have to go for the above custom solution, what are the pitfalls or potential issues I need to be aware of?
First of all when you remove login and there's no authentication mechanism in your application, there's really no way to secure anything, because anyone can access your APIs. I think what you want is to make sure that your APIs are called only from your own website. Unfortunately you can't completely achieve that, since your web APIs are http/https, and anyone, from anywhere (like postman, fiddler, ...) can create a http request and call your API.
All you can do is to make it harder for your API to response to requests, like using Anti-Forgery as you mentioned.
And also I suggest you add a cookie for your application and check that cookie in every request, in this case it's more complicated ( not impossible ) to call your API using Fiddler or Postman.
And last I suggest that you use CORS, so browsers would only allow your domain to call your APIs. So nobody can call your APIs in a browser from different domain.
Based on answer from #Arvin and comment from #Evk, here's how I plan to proceed:
Once, the user starts the anonymous session generate a GUID using regular Guid.NewGuid() method and save it in DB to identify the request (I'm doing this now). However, as mentioned here,
GUID can be unique but they are not cryptographically secured.
Hence, instead of using plain-text GUID, encrypt it with current timestamp as token and append it with request query string.
For every subsequent API request, read the token from query string, decrypt it and validate it as follows:
Check the timestamp. If the time difference is more than pre-defined time (i.e. token expired), reject the request
Validate the unique id (GUID) against DB
Since, I'm not using plain text GUID anymore, the URI would not easy to guess.
Additionally, with the timestamp, URI is invalidated after sometime. While theoretically it is still possible to call the API through Fiddler but this should make it very difficult for the attacker, if not impossible.
As a further security measure, I can also add Anti-Forgery token to the request
As per my understanding this helps solving my underlying problem and with this approach, I may not even need add a cookie to secure my anonymous session.
Love to hear from you all if this approach looks good and how can it be improved.
I also once had the weird need for having session functionality on WebAPI and created an OWIN Session middleware that does exactly what you're aiming for.
The library is called OwinSessionMiddleware and is available on github and NuGet.
Usage
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseSessionMiddleware();
// other middleware registrations...
app.UseWebApi();
}
}
You can also pass some options to further tweak cookie-name, add a database backed session store (instead of in-memory), add your own session id generator (instead of default id generator which is based on GUID + secure random part generated by RNGCryptoServiceProvider).
The unique session id itself is stored as a secure cookie and the session is restored automatically by the middleware on each request.
There are extension methods you can call inside your API controller to get and set session data:
public SomeApiController : ApiController
{
public IHttpActionResult MyAction()
{
var requestCount = Request.GetSessionProperty<int>("RequestCount");
Request.SetSessionProperty("RequestCount", ++requestCount);
}
}
Create Anonymous JWT token with some claims related to your scenario, Sign it with some key, Use that as in cookie (Http Only) or As bearer token. To make it little more harder further combine it with some cookies.
1)verify token signature and
2) Verify token expiry time
3) Verify Claim(skey) against cookies(skey)- no database storage required everything is in ur JWT token.

How to redirect a user to a different server and include HTTP basic authentication credentials?

I have a web application (C# - ASP.net) that needs to pass a user to a page on a remote Apache server using HTTP Basic Authentication. I need to be able to pass a user name and password to this server to allow users authenticated by my application to seamlessly use the other application without being prompted to enter credentials he doesn't have. The hand-off should be secure since both systems require SSL as long as the user name and password are not in client-side script. Is there a way to do this?
Basic authentication details are encoded in the request header named "Authorization" from the client. The header contains the base64 encoded result of "username:password".
e.g. Aladdin:open sesame = Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
There are more details on the Basic Access Auth wikipedia page.
For basic authentication, the Authorization header needs to be added to every request. Usually the browser will take care of this after the user has entered their credentials into the dialog presented by the browser. If you want to avoid having your users enter these credentials, then your ASP.net server will need to sit in between the user and the Apache server (acting as a reverse proxy) adding the auth headers to every request that it forwards on behalf of your users.
It is not possible to simply visit your server once and for it to add a "token" to the request then redirect to the apache server. This approach would be possible if you were using forms/cookies for authentication and your servers presented themselves to the user as within the same domain (e.g. asp.domain.com & apache.domain.com) then the auth cookie could be set on the parent domain (e.g. domain.com) and shared - see Forms Authentication across sub-domains.
Assuming that the basic auth scheme on the Apache server is not something you can easily change, it seems like the reverse proxy is the best option. In the reverse proxy code, the HttpWebRequest is the means to create each request to the apache server and add the additional authentication headers to it.
.net will deal with encoding the credentials in the proxied request using something like:
RemoteServer remoteServer = new RemoteServer(httpContext);
HttpWebRequest request = remoteServer.GetRequest();
request.PreAuthenticate = true;
request.Credentials = new NetworkCredential(UserName, SecurelyStoredPassword);
Try using the url format https://username:password#example.com
Only other thing I can think of - if the page doesnt force its way out, load a page of their site in a frame, send it data+ controls, via javascript so it sends the login and so on. Might be feasible.

Categories