How to mock private members? - c#

I have a service to work with some API. This API requires authorization, so I've decided to provide configuration model to service constructor, which contains auth info. Then constructor initializes RestClient with provided token.
client = new RestClient(config.Value.BaseUrl)
{
Authenticator = new HttpBasicAuthenticator(config.Value.Username, config.Value.Token)
};
Now I am trying to implement tests over this service and ran into a problem: I can not mock this RestClient because it is private.
Is there a way to solve this problem or I'll have to provide RestClient through constructor?

Related

How to access OWIN Authentication Options from outside the Owin authentication flow

Inside of my OwinStartup.cs, I defined an Authentication provider and set its options:
var authOptions = new AuthenticationOptions
{
ClientId = "myId",
ClientSecret = "verysecret"
};
app.UseMyAwesoneAuthentication(authOptions);
How can I get to the AuthenticationOptions object of the Authentication provider from within an ASP.Net MVC controller? I can access the OWIN context inside of the controller:
var owinContext = Request.GetOwinContext();
but have not found a way to get to the provider's AuthenticationOptions object other than making it a static object.
Is this okay?
EDIT: why am I doing this?
UseMyAwesomeAuthentication() is an extension method of my custom authentication provider, it adds the provider to the Owin IAppBuilder. Besides standard OAuth2 authentication against a 3rd party, the provider also has an extension method to fetch additional data from the 3rd party API using an access token obtained during initial authentication.
To call the 3rd party API outside of the Owin authentication process, the extension method needs access to the ClientID, ClientSecret and endpoint url data stored in the options object.
I changed the title to make it clearer what my actual objective is.

How do I store an access token for an external API in an ASP.NET Core server?

I have a ASP.NET Core 3.1 web server that, among other things, acts as a middleman between a front end Angular application and an external API service. It is supposed to make requests for data from the API service, which it will then deliver to the front end. To make requests to this API, it needs an OAuth 2 access token. To be clear, it is the server that authenticates itself to access data available under a public license, and not specific to individual users on my server.
I currently have it planned out to use two typed HttpClient classes (based on this article) and one Controller to expose endpoints. One typed HttpClient would have a method for authenticating the server and retrieving an access token to return, using a client secret the server knows. The other client would provide methods for retrieving specific data from the external API, using the access token retrieved by the first client. Finally, the Controller would use the second HttpClient to get data to return on its endpoints.
What eludes me is how to manage the access token provided by the first HttpClient. I imagine it would be best to only retrieve it when it's needed, and then store it until it runs out, and then request a new one. How do I do this, or some alternative?
Have an API client class which authenticates using your access client, then stores the access token, then use this class to make your API calls
public class ApiAccessClient
{
public ApiAccessClient(string clientSecret)
{
ClientSecret = clientSecret;
}
public async Task Authenticate()
{
// Authentication code
var response = await AuthClient.GetAsync(ClientSecret);
AccessToken = "Access_Token";
}
public string MakeApiCall()
{
// Use access token
return null;
}
private readonly string ClientSecret;
private string AccessToken;
private static HttpClient AuthClient;
private static HttpClient AccessClient;
}
Note the HTTP clients are static so that connections are reused, read more: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

How do I create a JWT for automated testing

Context
Our project has a collection of independent http services that work together we have
authentication service
service A
service B
service C
the purpose of A, B, & C is not important for this discussion. other than they interact with one another.
Authentication service is our implementation of Owin.Identity. Service A came online first and we (most likely) did not implement security integration correctly. We had to implement our own MachineKeyProtector to uprotect the identity and set the request context principal
var secureDataFormat = new TicketDataFormat(new MachineKeyProtector());
var ticket = secureDataFormat.Unprotect(accessToken);
request.GetRequestContext().Principal = new ClaimsPrincipal(ticket.Identity);
This already seems incorrect. I thought
//startup.cs
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
//web.config
//all our services share the same machine key
<machineKey decryptionKey="..." validationKey="..." validation="SHA1" decryption="AES" />
took care of security.
then comes the issue of automated tests. We are using Owin.Testing to mock HTTP calls and run integration tests. To get this to work, we need to create a JWT and we are currently using this code
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
var protected = new MachineKeyProtector().Protect(ticket);
new TicketDataFormat(protected);
again using our MachineKeyProtector implementation. All of this is working but it doesn't seem right. I would have through Owin.Security.OAuth (or JWT?) would handle this for us.
We created MachineKeyProtector as a way to generate JWT tokens for our automated tests.
Questions/Problems
How can we generate a JWT without implementing our own MachineKeyProtector. I would assume there is a JwtTokenizer.Create(new Claims Identity()); call we could use to generate the authentication token, but I haven't been able to find it.
How do we configure security in service A, B, & C so the request principal is set without us setting it explicitly?
I tried to keep the context as simple as possible while providing some insight into where we currently are. If more information is need please ask.

IdentityServer3 - 401 Unauthorized when calling Identity API Controller

I have a project which uses IdentityServer3 for Auth as a Service.
Recently I was tasked with creating a seamless experience for End-Users to edit their identity information.
I did this by creating an API Controller in my application which uses a HTTPClient to call another API Controller living in my IdentityServer project. It basically exposes the Identity management methods to the world, but "passes-through" any requests on to the IdentityServer Api.
All is well right up until I call the IdentityServer Api Controller. My breakpoint there is never hit, regardless of the presence of a "Authorize" attribute. I end up receiving a "401: Unauthorized" back from the IdentityServer Api controller.
I've tried to reuse the original request's Auth headers, but that didn't work. I also tried to find a "access_token" claim from my claim principle, but one wasn't found.
here is a code snippet:
var httpClient = new HttpClient();
// this didn't work - tried reusing the auth from the original request
//httpClient.DefaultRequestHeaders.Authorization = request.Headers.Authorization;
// this didn't work either - "access_token" is not found
//httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", Caller.FindFirst("access_token").Value);
var routePrefix = GetRoutePrefix();
var response = await httpClient.PostAsync(
$"{routePrefix}/post",
new ObjectContent(typeof(TDObj), entity, new JsonMediaTypeFormatter()));
return response;
I'm new to IdentityServer3 and OAuth and not sure what to do next. I tried creating a new scope for "identity" and tried to make it a required scope in my client application, but that didn't seem to do the trick. I know I'm missing some key piece of understanding here, but there is so much documentation for IdentityServer, I don't know where to begin and can't find anything specific to this need. I'm in the weeds! Can anyone help me understand what's going on here? Thanks!
I got it working by following Scott Brady's answer here: Identity Server and web api for user management
However, his answer didn't immediately work for me. I had to make sure to make the call for UseIdentityServerTokenValidation to happen BEFORE api route mapping happened.
That being said, my original attempt to hi-jack the Authorization headers from the inbound HTTPRequest of my Front-End application worked, so I was able to remove any code requesting an access token and didn't have to SetBearerToken() on my HttpClient. Just this:
httpClient.DefaultRequestHeaders.Authorization = request.Headers.Authorization;

Modifying OWIN OAuth middleware to use JWT bearer tokens

I'm currently trying to create a proof of concept for claims based authentication for a new app using a combination of the following technologies: Web API 2, OWIN middleware and JWT.
To keep things simple I started with the Web API 2 project template and changed the authentication to 'Individual User Accounts'. The sample client I created was then able to get a token by calling /Token and was able to call a sample endpoint with the OAuth bearer token. So far so good. I then added the following code to Startup.Auth.cs to try and enable JwtBearerAuthentication:
var jwtOptions = new JwtBearerAuthenticationOptions
{
AllowedAudiences = audiences,
IssuerSecurityTokenProviders = new[] {
new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey) }
};
app.UseJwtBearerAuthentication(jwtOptions);
I expected that Web API 2 would start returning JWTs from the call to /Token, but it doesn't appear to have done anything. I've been banging my head against this for a few days with no success and the Microsoft documents aren't very forthcoming.
I also tried adding the following to my OAuthAuthorizationServerOptions
AuthorizationCodeFormat = new JwtFormat(audience, new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey))
I could also be trying to doing the completely wrong thing.
Any ideas would be greatly appreciated.
Well, now there is a setting on OAuthAuthorizationServerOptions that you can specify the format of your access token, not the authorization code, like you're doing on you example.
So, instead of:
AuthorizationCodeFormat = new JwtFormat(audience, new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey))
You should have:
AccessTokenFormat = new JwtFormat(audience, new SymmetricKeyIssuerSecurityTokenProvider(issuer, signingKey))
The Windows Identity Foundation uses a proprietary token format, not JWT. The JWT code you see above is for consuming tokens, not generating them. There is a helpful discussion on the ASP.NET forums.
However, in the second half of 2014 Microsoft officially released support for JWT in Windows Identity foundation, with the JSON Web Token Handler. You should be able to install and use that package to solve the problem you have described.
I don't think there's any current way to override how the token is output in the response. I took a look at the OAuthAuthorizationServerHandler in the Katana source code repository.
You'll see that in the InvokeTokenEndpointAsync method, there is a section that creates a JsonTextWriter which generates the response. It is not done in such a way that any kind of extension would affect it.
I find this frustrating too. Microsoft's library should have some way to easily override the response serialization. You can't even add your own custom parameters to the response.
You can use this sample https://github.com/thinktecture/Thinktecture.IdentityModel/tree/master/samples/OAuth2/EmbeddedResourceOwnerFlow
for writting authentication logic in your project.
After it you must add [Authorize] attribute to each controller or action which requires authorization(OWIN Katana contains the logic of validating token, authorization and some other useful things).

Categories