1
1
// Copyright (c) .NET Foundation. All rights reserved.
2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
+ using System ;
4
5
using System . Collections . Generic ;
5
6
using System . IO ;
6
7
using System . Linq ;
@@ -51,53 +52,42 @@ public async Task ValidTokenIsAccepted()
51
52
var response = await httpClient . GetAsync ( "/" ) ;
52
53
var queryItems = QueryHelpers . ParseQuery ( response . Headers . Location . Query ) ;
53
54
54
- // Send an invalid token and verify that the token is not honored
55
- var kvps = new List < KeyValuePair < string , string > > ( ) ;
56
- kvps . Add ( new KeyValuePair < string , string > ( "wa" , "wsignin1.0" ) ) ;
57
- kvps . Add ( new KeyValuePair < string , string > ( "wresult" , File . ReadAllText ( @"ValidToken.xml" ) ) ) ;
58
- kvps . Add ( new KeyValuePair < string , string > ( "wctx" , queryItems [ "wctx" ] ) ) ;
59
- response = await httpClient . PostAsync ( queryItems [ "wreply" ] , new FormUrlEncodedContent ( kvps ) ) ;
55
+ var request = new HttpRequestMessage ( HttpMethod . Post , queryItems [ "wreply" ] ) ;
56
+ CopyCookies ( response , request ) ;
57
+ request . Content = CreateSignInContent ( "ValidToken.xml" , queryItems [ "wctx" ] ) ;
58
+ response = await httpClient . SendAsync ( request ) ;
60
59
61
60
Assert . Equal ( HttpStatusCode . Found , response . StatusCode ) ;
62
61
63
- var request = new HttpRequestMessage ( HttpMethod . Get , response . Headers . Location ) ;
64
- var cookies = SetCookieHeaderValue . ParseList ( response . Headers . GetValues ( HeaderNames . SetCookie ) . ToList ( ) ) ;
65
- foreach ( var cookie in cookies )
66
- {
67
- if ( cookie . Value . HasValue )
68
- {
69
- request . Headers . Add ( HeaderNames . Cookie , new CookieHeaderValue ( cookie . Name , cookie . Value ) . ToString ( ) ) ;
70
- }
71
- }
62
+ request = new HttpRequestMessage ( HttpMethod . Get , response . Headers . Location ) ;
63
+ CopyCookies ( response , request ) ;
72
64
response = await httpClient . SendAsync ( request ) ;
73
65
74
66
// Did the request end in the actual resource requested for
75
67
Assert . Equal ( WsFederationDefaults . AuthenticationScheme , await response . Content . ReadAsStringAsync ( ) ) ;
76
68
}
77
69
78
70
[ Fact ]
79
- public async Task ValidUnsolicitedTokenIsAccepted ( )
71
+ public async Task ValidUnsolicitedTokenIsRefused ( )
80
72
{
81
73
var httpClient = CreateClient ( ) ;
74
+ var form = CreateSignInContent ( "ValidToken.xml" , suppressWctx : true ) ;
75
+ var exception = await Assert . ThrowsAsync < Exception > ( ( ) => httpClient . PostAsync ( httpClient . BaseAddress + "signin-wsfed" , form ) ) ;
76
+ Assert . Contains ( "Unsolicited logins are not allowed." , exception . Message ) ;
77
+ }
82
78
83
- // Send an invalid token and verify that the token is not honored
84
- var kvps = new List < KeyValuePair < string , string > > ( ) ;
85
- kvps . Add ( new KeyValuePair < string , string > ( "wa" , "wsignin1.0" ) ) ;
86
- kvps . Add ( new KeyValuePair < string , string > ( "wresult" , File . ReadAllText ( @"ValidToken.xml" ) ) ) ;
87
- kvps . Add ( new KeyValuePair < string , string > ( "suppressWctx" , "true" ) ) ;
88
- var response = await httpClient . PostAsync ( httpClient . BaseAddress + "signin-wsfed" , new FormUrlEncodedContent ( kvps ) ) ;
79
+ [ Fact ]
80
+ public async Task ValidUnsolicitedTokenIsAcceptedWhenAllowed ( )
81
+ {
82
+ var httpClient = CreateClient ( allowUnsolicited : true ) ;
83
+
84
+ var form = CreateSignInContent ( "ValidToken.xml" , suppressWctx : true ) ;
85
+ var response = await httpClient . PostAsync ( httpClient . BaseAddress + "signin-wsfed" , form ) ;
89
86
90
87
Assert . Equal ( HttpStatusCode . Found , response . StatusCode ) ;
91
88
92
89
var request = new HttpRequestMessage ( HttpMethod . Get , response . Headers . Location ) ;
93
- var cookies = SetCookieHeaderValue . ParseList ( response . Headers . GetValues ( HeaderNames . SetCookie ) . ToList ( ) ) ;
94
- foreach ( var cookie in cookies )
95
- {
96
- if ( cookie . Value . HasValue )
97
- {
98
- request . Headers . Add ( HeaderNames . Cookie , new CookieHeaderValue ( cookie . Name , cookie . Value ) . ToString ( ) ) ;
99
- }
100
- }
90
+ CopyCookies ( response , request ) ;
101
91
response = await httpClient . SendAsync ( request ) ;
102
92
103
93
// Did the request end in the actual resource requested for
@@ -113,94 +103,119 @@ public async Task InvalidTokenIsRejected()
113
103
var response = await httpClient . GetAsync ( "/" ) ;
114
104
var queryItems = QueryHelpers . ParseQuery ( response . Headers . Location . Query ) ;
115
105
116
- // Send an invalid token and verify that the token is not honored
117
- var kvps = new List < KeyValuePair < string , string > > ( ) ;
118
- kvps . Add ( new KeyValuePair < string , string > ( "wa" , "wsignin1.0" ) ) ;
119
- kvps . Add ( new KeyValuePair < string , string > ( "wresult" , File . ReadAllText ( @"InvalidToken.xml" ) ) ) ;
120
- kvps . Add ( new KeyValuePair < string , string > ( "wctx" , queryItems [ "wctx" ] ) ) ;
121
- response = await httpClient . PostAsync ( queryItems [ "wreply" ] , new FormUrlEncodedContent ( kvps ) ) ;
106
+ var request = new HttpRequestMessage ( HttpMethod . Post , queryItems [ "wreply" ] ) ;
107
+ CopyCookies ( response , request ) ;
108
+ request . Content = CreateSignInContent ( "InvalidToken.xml" , queryItems [ "wctx" ] ) ;
109
+ response = await httpClient . SendAsync ( request ) ;
122
110
123
111
// Did the request end in the actual resource requested for
124
112
Assert . Equal ( "AuthenticationFailed" , await response . Content . ReadAsStringAsync ( ) ) ;
125
113
}
126
114
127
- private HttpClient CreateClient ( )
115
+ private FormUrlEncodedContent CreateSignInContent ( string tokenFile , string wctx = null , bool suppressWctx = false )
128
116
{
129
- var builder = new WebHostBuilder ( )
130
- . ConfigureServices ( ConfigureAppServices )
131
- . Configure ( ConfigureApp ) ;
132
- var server = new TestServer ( builder ) ;
133
- return server . CreateClient ( ) ;
117
+ var kvps = new List < KeyValuePair < string , string > > ( ) ;
118
+ kvps . Add ( new KeyValuePair < string , string > ( "wa" , "wsignin1.0" ) ) ;
119
+ kvps . Add ( new KeyValuePair < string , string > ( "wresult" , File . ReadAllText ( tokenFile ) ) ) ;
120
+ if ( ! string . IsNullOrEmpty ( wctx ) )
121
+ {
122
+ kvps . Add ( new KeyValuePair < string , string > ( "wctx" , wctx ) ) ;
123
+ }
124
+ if ( suppressWctx )
125
+ {
126
+ kvps . Add ( new KeyValuePair < string , string > ( "suppressWctx" , "true" ) ) ;
127
+ }
128
+ return new FormUrlEncodedContent ( kvps ) ;
134
129
}
135
130
136
- private void ConfigureAppServices ( IServiceCollection services )
131
+ private void CopyCookies ( HttpResponseMessage response , HttpRequestMessage request )
137
132
{
138
- services . AddAuthentication ( sharedOptions =>
139
- {
140
- sharedOptions . DefaultScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
141
- sharedOptions . DefaultSignInScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
142
- sharedOptions . DefaultChallengeScheme = WsFederationDefaults . AuthenticationScheme ;
143
- } )
144
- . AddWsFederation ( options =>
133
+ var cookies = SetCookieHeaderValue . ParseList ( response . Headers . GetValues ( HeaderNames . SetCookie ) . ToList ( ) ) ;
134
+ foreach ( var cookie in cookies )
145
135
{
146
- options . Wtrealm = "http://Automation1" ;
147
- options . MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml" ;
148
- options . BackchannelHttpHandler = new WaadMetadataDocumentHandler ( ) ;
149
- options . StateDataFormat = new CustomStateDataFormat ( ) ;
150
- options . SecurityTokenHandlers = new List < ISecurityTokenValidator > ( ) { new TestSecurityTokenValidator ( ) } ;
151
- options . UseTokenLifetime = false ;
152
- options . Events = new WsFederationEvents ( )
136
+ if ( cookie . Value . HasValue )
137
+ {
138
+ request . Headers . Add ( HeaderNames . Cookie , new CookieHeaderValue ( cookie . Name , cookie . Value ) . ToString ( ) ) ;
139
+ }
140
+ }
141
+ }
142
+
143
+ private HttpClient CreateClient ( bool allowUnsolicited = false )
144
+ {
145
+ var builder = new WebHostBuilder ( )
146
+ . Configure ( ConfigureApp )
147
+ . ConfigureServices ( services =>
153
148
{
154
- MessageReceived = context =>
149
+ services . AddAuthentication ( sharedOptions =>
155
150
{
156
- if ( ! context . ProtocolMessage . Parameters . TryGetValue ( "suppressWctx" , out var suppress ) )
157
- {
158
- Assert . True ( context . ProtocolMessage . Wctx . Equals ( "customValue" ) , "wctx is not my custom value" ) ;
159
- }
160
- context . HttpContext . Items [ "MessageReceived" ] = true ;
161
- return Task . FromResult ( 0 ) ;
162
- } ,
163
- RedirectToIdentityProvider = context =>
151
+ sharedOptions . DefaultScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
152
+ sharedOptions . DefaultSignInScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
153
+ sharedOptions . DefaultChallengeScheme = WsFederationDefaults . AuthenticationScheme ;
154
+ } )
155
+ . AddCookie ( )
156
+ . AddWsFederation ( options =>
164
157
{
165
- if ( context . ProtocolMessage . IsSignInMessage )
158
+ options . Wtrealm = "http://Automation1" ;
159
+ options . MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml" ;
160
+ options . BackchannelHttpHandler = new WaadMetadataDocumentHandler ( ) ;
161
+ options . StateDataFormat = new CustomStateDataFormat ( ) ;
162
+ options . SecurityTokenHandlers = new List < ISecurityTokenValidator > ( ) { new TestSecurityTokenValidator ( ) } ;
163
+ options . UseTokenLifetime = false ;
164
+ options . AllowUnsolicitedLogins = allowUnsolicited ;
165
+ options . Events = new WsFederationEvents ( )
166
166
{
167
- // Sign in message
168
- context . ProtocolMessage . Wctx = "customValue" ;
169
- }
167
+ MessageReceived = context =>
168
+ {
169
+ if ( ! context . ProtocolMessage . Parameters . TryGetValue ( "suppressWctx" , out var suppress ) )
170
+ {
171
+ Assert . True ( context . ProtocolMessage . Wctx . Equals ( "customValue" ) , "wctx is not my custom value" ) ;
172
+ }
173
+ context . HttpContext . Items [ "MessageReceived" ] = true ;
174
+ return Task . FromResult ( 0 ) ;
175
+ } ,
176
+ RedirectToIdentityProvider = context =>
177
+ {
178
+ if ( context . ProtocolMessage . IsSignInMessage )
179
+ {
180
+ // Sign in message
181
+ context . ProtocolMessage . Wctx = "customValue" ;
182
+ }
170
183
171
- return Task . FromResult ( 0 ) ;
172
- } ,
173
- SecurityTokenReceived = context =>
174
- {
175
- context . HttpContext . Items [ "SecurityTokenReceived" ] = true ;
176
- return Task . FromResult ( 0 ) ;
177
- } ,
178
- SecurityTokenValidated = context =>
179
- {
180
- Assert . True ( ( bool ) context . HttpContext . Items [ "MessageReceived" ] , "MessageReceived notification not invoked" ) ;
181
- Assert . True ( ( bool ) context . HttpContext . Items [ "SecurityTokenReceived" ] , "SecurityTokenReceived notification not invoked" ) ;
184
+ return Task . FromResult ( 0 ) ;
185
+ } ,
186
+ SecurityTokenReceived = context =>
187
+ {
188
+ context . HttpContext . Items [ "SecurityTokenReceived" ] = true ;
189
+ return Task . FromResult ( 0 ) ;
190
+ } ,
191
+ SecurityTokenValidated = context =>
192
+ {
193
+ Assert . True ( ( bool ) context . HttpContext . Items [ "MessageReceived" ] , "MessageReceived notification not invoked" ) ;
194
+ Assert . True ( ( bool ) context . HttpContext . Items [ "SecurityTokenReceived" ] , "SecurityTokenReceived notification not invoked" ) ;
182
195
183
- if ( context . Principal != null )
184
- {
185
- var identity = context . Principal . Identities . Single ( ) ;
186
- identity . AddClaim ( new Claim ( "ReturnEndpoint" , "true" ) ) ;
187
- identity . AddClaim ( new Claim ( "Authenticated" , "true" ) ) ;
188
- identity . AddClaim ( new Claim ( identity . RoleClaimType , "Guest" , ClaimValueTypes . String ) ) ;
189
- }
190
-
191
- return Task . FromResult ( 0 ) ;
192
- } ,
193
- AuthenticationFailed = context =>
194
- {
195
- context . HttpContext . Items [ "AuthenticationFailed" ] = true ;
196
- //Change the request url to something different and skip Wsfed. This new url will handle the request and let us know if this notification was invoked.
197
- context . HttpContext . Request . Path = new PathString ( "/AuthenticationFailed" ) ;
198
- context . SkipHandler ( ) ;
199
- return Task . FromResult ( 0 ) ;
200
- }
201
- } ;
202
- } )
203
- . AddCookie ( ) ;
196
+ if ( context . Principal != null )
197
+ {
198
+ var identity = context . Principal . Identities . Single ( ) ;
199
+ identity . AddClaim ( new Claim ( "ReturnEndpoint" , "true" ) ) ;
200
+ identity . AddClaim ( new Claim ( "Authenticated" , "true" ) ) ;
201
+ identity . AddClaim ( new Claim ( identity . RoleClaimType , "Guest" , ClaimValueTypes . String ) ) ;
202
+ }
203
+
204
+ return Task . FromResult ( 0 ) ;
205
+ } ,
206
+ AuthenticationFailed = context =>
207
+ {
208
+ context . HttpContext . Items [ "AuthenticationFailed" ] = true ;
209
+ //Change the request url to something different and skip Wsfed. This new url will handle the request and let us know if this notification was invoked.
210
+ context . HttpContext . Request . Path = new PathString ( "/AuthenticationFailed" ) ;
211
+ context . SkipHandler ( ) ;
212
+ return Task . FromResult ( 0 ) ;
213
+ }
214
+ } ;
215
+ } ) ;
216
+ } ) ;
217
+ var server = new TestServer ( builder ) ;
218
+ return server . CreateClient ( ) ;
204
219
}
205
220
206
221
private void ConfigureApp ( IApplicationBuilder app )
0 commit comments