1
1
using System . Globalization ;
2
2
using System . Net ;
3
+ using System . Net . Http . Headers ;
3
4
using System . Security . Cryptography ;
5
+ using System . Text ;
4
6
using Microsoft . AspNetCore . WebUtilities ;
5
7
using Microsoft . Extensions . Configuration ;
6
8
using Microsoft . Extensions . DependencyInjection ;
@@ -18,19 +20,21 @@ public class OAuthHttpClientTests : IClassFixture<OAuthFixture>
18
20
private readonly MockHttpMessageHandler ? _mockHttp ;
19
21
private readonly IRequestSigner _signer = new HmacSha1RequestSigner ( ) ;
20
22
private readonly IConfiguration _configuration ;
23
+ private readonly OAuthCredential _clientCredentials ;
21
24
private readonly OAuthCredential _tokenCredentials ;
22
25
23
26
public OAuthHttpClientTests ( OAuthFixture fixture )
24
27
{
25
28
_configuration = fixture . Configuration ;
29
+ _clientCredentials = new OAuthCredential (
30
+ _configuration [ "OAuth:ClientId" ] ,
31
+ _configuration [ "OAuth:ClientSecret" ] ) ;
26
32
_tokenCredentials = new OAuthCredential (
27
33
_configuration [ "OAuth:TokenId" ] ,
28
34
_configuration [ "OAuth:TokenSecret" ] ) ;
29
- if ( _configuration . GetValue ( "HttpClient:Mock" , true ) )
30
- {
31
- _mockHttp = new MockHttpMessageHandler ( ) ;
32
- _mockHttp . Fallback . Respond ( HttpStatusCode . Unauthorized ) ;
33
- }
35
+ if ( ! _configuration . GetValue ( "HttpClient:Mock" , true ) ) return ;
36
+ _mockHttp = new MockHttpMessageHandler ( ) ;
37
+ _mockHttp . Fallback . Respond ( HttpStatusCode . Unauthorized ) ;
34
38
}
35
39
36
40
[ Fact ]
@@ -40,18 +44,14 @@ public async Task HttpClient_AccessProtectedResourceWithAuthorizationHeader_Shou
40
44
var services = new ServiceCollection ( )
41
45
. AddOAuthHttpClient < OAuthHttpClient > ( ( _ , handlerOptions ) =>
42
46
{
43
- handlerOptions . ClientCredentials = new OAuthCredential (
44
- _configuration [ "OAuth:ClientId" ] ,
45
- _configuration [ "OAuth:ClientSecret" ] ) ;
47
+ handlerOptions . ClientCredentials = _clientCredentials ;
46
48
handlerOptions . TokenCredentials = _tokenCredentials ;
47
- if ( _mockHttp != null )
48
- {
49
- var timestamp = DateTimeOffset . UtcNow . ToUnixTimeSeconds ( )
50
- . ToString ( CultureInfo . InvariantCulture ) ;
51
- var nonce = generateNonce ( ) ;
52
- handlerOptions . TimestampProvider = ( ) => timestamp ;
53
- handlerOptions . NonceProvider = ( ) => nonce ;
54
- }
49
+ if ( _mockHttp == null ) return ;
50
+ var timestamp = DateTimeOffset . UtcNow . ToUnixTimeSeconds ( )
51
+ . ToString ( CultureInfo . InvariantCulture ) ;
52
+ var nonce = GenerateNonce ( ) ;
53
+ handlerOptions . TimestampProvider = ( ) => timestamp ;
54
+ handlerOptions . NonceProvider = ( ) => nonce ;
55
55
} )
56
56
. ConfigurePrimaryHttpMessageHandler ( _ => _mockHttp ?? new HttpClientHandler ( ) as HttpMessageHandler )
57
57
. Services . BuildServiceProvider ( ) ;
@@ -72,6 +72,36 @@ public async Task HttpClient_AccessProtectedResourceWithAuthorizationHeader_Shou
72
72
_mockHttp ? . VerifyNoOutstandingExpectation ( ) ;
73
73
_mockHttp ? . VerifyNoOutstandingRequest ( ) ;
74
74
}
75
+
76
+ [ Fact ]
77
+ public async Task HttpClient_AccessProtectedResourceWithPredefinedAuthorizationHeader_ShouldPassThrough ( )
78
+ {
79
+ // Arrange
80
+ var services = new ServiceCollection ( )
81
+ . AddOAuthHttpClient < OAuthHttpClient > ( ( _ , handlerOptions ) =>
82
+ {
83
+ handlerOptions . ClientCredentials = _clientCredentials ;
84
+ handlerOptions . TokenCredentials = _tokenCredentials ;
85
+ } )
86
+ . ConfigurePrimaryHttpMessageHandler ( _ => _mockHttp ?? new HttpClientHandler ( ) as HttpMessageHandler )
87
+ . Services . BuildServiceProvider ( ) ;
88
+ var client = services . GetRequiredService < OAuthHttpClient > ( ) ;
89
+ var resourceUri = _configuration . GetValue < Uri > ( "Request:Uri" ) ;
90
+ var basicAuth = Convert . ToBase64String ( Encoding . ASCII . GetBytes ( $ "{ _clientCredentials . Key } :{ _clientCredentials . Secret } ") ) ;
91
+ _mockHttp ? . Expect ( HttpMethod . Get , resourceUri . AbsoluteUri )
92
+ . WithHeaders ( "Authorization" , $ "Basic { basicAuth } ")
93
+ . Respond ( HttpStatusCode . Forbidden ) ;
94
+
95
+ // Act
96
+ using var request = new HttpRequestMessage ( HttpMethod . Get , resourceUri ) ;
97
+ request . Headers . Authorization = new AuthenticationHeaderValue ( "Basic" , basicAuth ) ;
98
+ var response = await client . HttpClient . SendAsync ( request ) . ConfigureAwait ( false ) ;
99
+
100
+ // Assert
101
+ Assert . Equal ( HttpStatusCode . Forbidden , response . StatusCode ) ;
102
+ _mockHttp ? . VerifyNoOutstandingExpectation ( ) ;
103
+ _mockHttp ? . VerifyNoOutstandingRequest ( ) ;
104
+ }
75
105
76
106
[ Fact ]
77
107
public async Task HttpClient_AccessProtectedResourceWithQueryString_ShouldAuthorized ( )
@@ -80,19 +110,15 @@ public async Task HttpClient_AccessProtectedResourceWithQueryString_ShouldAuthor
80
110
var services = new ServiceCollection ( )
81
111
. AddOAuthHttpClient < OAuthHttpClient > ( ( _ , handlerOptions ) =>
82
112
{
83
- handlerOptions . ClientCredentials = new OAuthCredential (
84
- _configuration [ "OAuth:ClientId" ] ,
85
- _configuration [ "OAuth:ClientSecret" ] ) ;
113
+ handlerOptions . ClientCredentials = _clientCredentials ;
86
114
handlerOptions . TokenCredentials = _tokenCredentials ;
87
115
handlerOptions . SignedAsQuery = true ;
88
- if ( _mockHttp != null )
89
- {
90
- var timestamp = DateTimeOffset . UtcNow . ToUnixTimeSeconds ( )
91
- . ToString ( CultureInfo . InvariantCulture ) ;
92
- var nonce = generateNonce ( ) ;
93
- handlerOptions . TimestampProvider = ( ) => timestamp ;
94
- handlerOptions . NonceProvider = ( ) => nonce ;
95
- }
116
+ if ( _mockHttp == null ) return ;
117
+ var timestamp = DateTimeOffset . UtcNow . ToUnixTimeSeconds ( )
118
+ . ToString ( CultureInfo . InvariantCulture ) ;
119
+ var nonce = GenerateNonce ( ) ;
120
+ handlerOptions . TimestampProvider = ( ) => timestamp ;
121
+ handlerOptions . NonceProvider = ( ) => nonce ;
96
122
} )
97
123
. ConfigurePrimaryHttpMessageHandler ( _ => _mockHttp ?? new HttpClientHandler ( ) as HttpMessageHandler )
98
124
. Services . BuildServiceProvider ( ) ;
@@ -104,14 +130,7 @@ public async Task HttpClient_AccessProtectedResourceWithQueryString_ShouldAuthor
104
130
: "?foo=v1&foo=v2" ;
105
131
var parameters = _signer . AppendAuthorizationParameters ( HttpMethod . Get , resourceUri . Uri ,
106
132
options . Value , QueryHelpers . ParseQuery ( resourceUri . Uri . Query ) , _tokenCredentials ) ;
107
- var values = new List < string > ( ) ;
108
- foreach ( var parameter in parameters )
109
- {
110
- foreach ( var value in parameter . Value )
111
- {
112
- values . Add ( $ "{ Uri . EscapeDataString ( parameter . Key ) } ={ Uri . EscapeDataString ( value ) } ") ;
113
- }
114
- }
133
+ var values = ( from parameter in parameters from value in parameter . Value select $ "{ Uri . EscapeDataString ( parameter . Key ) } ={ Uri . EscapeDataString ( value ) } ") . ToList ( ) ;
115
134
116
135
_mockHttp ? . Expect ( HttpMethod . Get , resourceUri . Uri . AbsoluteUri )
117
136
. WithQueryString ( "?" + string . Join ( "&" , values ) )
@@ -133,19 +152,15 @@ public async Task HttpClient_AccessProtectedResourceWithFormBody_ShouldAuthorize
133
152
var services = new ServiceCollection ( )
134
153
. AddOAuthHttpClient < OAuthHttpClient > ( ( _ , handlerOptions ) =>
135
154
{
136
- handlerOptions . ClientCredentials = new OAuthCredential (
137
- _configuration [ "OAuth:ClientId" ] ,
138
- _configuration [ "OAuth:ClientSecret" ] ) ;
155
+ handlerOptions . ClientCredentials = _clientCredentials ;
139
156
handlerOptions . TokenCredentials = _tokenCredentials ;
140
157
handlerOptions . SignedAsBody = true ;
141
- if ( _mockHttp != null )
142
- {
143
- var timestamp = DateTimeOffset . UtcNow . ToUnixTimeSeconds ( )
144
- . ToString ( CultureInfo . InvariantCulture ) ;
145
- var nonce = generateNonce ( ) ;
146
- handlerOptions . TimestampProvider = ( ) => timestamp ;
147
- handlerOptions . NonceProvider = ( ) => nonce ;
148
- }
158
+ if ( _mockHttp == null ) return ;
159
+ var timestamp = DateTimeOffset . UtcNow . ToUnixTimeSeconds ( )
160
+ . ToString ( CultureInfo . InvariantCulture ) ;
161
+ var nonce = GenerateNonce ( ) ;
162
+ handlerOptions . TimestampProvider = ( ) => timestamp ;
163
+ handlerOptions . NonceProvider = ( ) => nonce ;
149
164
} )
150
165
. ConfigurePrimaryHttpMessageHandler ( _ => _mockHttp ?? new HttpClientHandler ( ) as HttpMessageHandler )
151
166
. Services . BuildServiceProvider ( ) ;
@@ -193,7 +208,7 @@ public async Task HttpClient_AccessProtectedResourceWithFormBody_ShouldAuthorize
193
208
_mockHttp ? . VerifyNoOutstandingRequest ( ) ;
194
209
}
195
210
196
- private static string generateNonce ( )
211
+ private static string GenerateNonce ( )
197
212
{
198
213
var bytes = new byte [ 16 ] ;
199
214
_randomNumberGenerator . GetNonZeroBytes ( bytes ) ;
0 commit comments