-
Notifications
You must be signed in to change notification settings - Fork 587
WsFederation review #1441
WsFederation review #1441
Conversation
|
@Tratcher, |
|
We have a build plan, @JunTaoLuo will be in charge of that. We'll start as soon as we get code sign-off from @HaoK. |
| services.AddAuthentication(sharedOptions => | ||
| { | ||
| sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; | ||
| sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: doesn't DefaultSignInScheme fallback to DefaultScheme?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not correctly in the 2.0.0 branch we're targeting. That was just fixed in 2.1 and 2.0.x.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh, yeah that's too bad
|
|
||
| if (context.Request.Path.Equals("/signout")) | ||
| { | ||
| await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this just use the empty overload since you are setting the defaults?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could. This just mirrors the template code.
samples/WsFedSample/Startup.cs
Outdated
|
|
||
| if (context.Request.Path.Equals("/Account/AccessDenied")) | ||
| { | ||
| await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does AccessDenied sign out?
| /// <summary> | ||
| /// The context object used in for <see cref="WsFederationEvents.AuthenticationFailed"/>. | ||
| /// </summary> | ||
| public class AuthenticationFailedContext : RemoteAuthenticationContext<WsFederationOptions> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: should this have a more specific name, i.e. WsFedFailedContext?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shrug I don't see why it needs one. This type will rarely be referenced by name, and if you really need to and have a conflict you can do WsFederation.AuthenticationFailedContext.
| try | ||
| { | ||
| // Retrieve our cached redirect uri | ||
| string state = wsFederationMessage.Wctx; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: var?
| else | ||
| { | ||
| // Extract the user state from properties and reset. | ||
| properties.Items.TryGetValue(WsFederationDefaults.UserstatePropertiesKey, out var userState); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this do something if TryGetvalue fails? Or is that ok to just ignore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's optional.
| if (wsFederationMessage.Wresult == null) | ||
| { | ||
| Logger.LogWarning("Received a sign-in message without a WResult."); | ||
| return (HandleRequestResult)HandleRequestResult.NoResult(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the cast?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, NoResult returns the base type AuthenticateResult.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why using NoResult here? A WS-Fed sign-in response without a wresult parameter is illegal so this should return an errored result.
|
|
||
| // Copy and augment to avoid cross request race conditions for updated configurations. | ||
| var tvp = Options.TokenValidationParameters.Clone(); | ||
| IEnumerable<string> issuers = new[] { _configuration.Issuer }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: var?
| break; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the validator contract that if principal != null, parsedToken will be non null? Should this check parsedToken as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, ValidateToken always returns both a ClaimsPrincipal and a parsedToken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still might be safer to just check principal != null && parsedToken != null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We only reference the token for the expiration values, so I'll check there.
| /// <summary> | ||
| /// Gets or sets the collection of <see cref="ISecurityTokenValidator"/> used to read and validate the <see cref="SecurityToken"/>s. | ||
| /// </summary> | ||
| [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "By design")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we remove this supression and just throw the argument exception with parameter name correctly?
| /// <summary> | ||
| /// Gets or sets the AuthenticationType used when creating the <see cref="System.Security.Claims.ClaimsIdentity"/>. | ||
| /// </summary> | ||
| public string SignInAsAuthenticationType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: SignInAuthenticationType? Does the As add anything? This is what we use along with SignInScheme right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obsolete, removed.
| /// Gets or sets the <see cref="TokenValidationParameters"/> | ||
| /// </summary> | ||
| /// <exception cref="ArgumentNullException"> if 'TokenValidationParameters' is null.</exception> | ||
| [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "Name of the property.")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove? use nameof for exceptions everywhere as well instead of constants.
| public string Protect(AuthenticationProperties data) | ||
| { | ||
| lastSavedAuthenticationProperties = Serialize(data); | ||
| return "ValidStateData"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: use a const?
| var server = new TestServer(builder); | ||
|
|
||
| var httpClient = server.CreateClient(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move all the builder/server/client creation into a CreateClient(), the tests all seem to only use httpClient right?
HaoK
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine in general, just some minor stuff
| services.AddAuthentication(sharedOptions => | ||
| { | ||
| sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; | ||
| sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do today due to the 2.0.x patch bug.
JunTaoLuo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding build-related items (*.csproj, etc)
b3b8950 to
7fc888f
Compare
| if (string.IsNullOrEmpty(token)) | ||
| { | ||
| Logger.LogWarning("Received a sign-in message without a token."); | ||
| return (HandleRequestResult)HandleRequestResult.NoResult(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same remark. Plus it's inconsistent with the OIDC handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a direct equivalent in OIDC, it detects correct messages by looking for State and CorrelationId, both of which are optional for WsFed. That said, we should probably be using the SkipUnrecognizedRequests pattern here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, we should probably be using the SkipUnrecognizedRequests pattern here.
It's something you're already doing at line 129 by making an IsSignInMessage check, which ensures that a wa parameter is present and corresponds to a sign-in operation. Once this check is made, you can consider the request as a valid WS-Fed message. Every missing parameter that is marked as required by the spec should result in an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair.
|
@Tratcher it's 2017 and CSRF/session fixation attacks are no longer cool so please consider adding built-in antiforgery support like what we have in the OIDC handler. To support unsolicited assertions, an opt-in option |
|
The anti-xsrf with an opt-out is an interesting suggestion. I'll open a new issue for that. |
7fc888f to
674145d
Compare
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.0.0" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to cause issues. You should always use a ProjectReference to anything that is built from the same repo.
cc @JunTaoLuo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see why this fails universe. We will build this for this release without using Universe as I'll build locally instead. The reason we wanted to take this approach is because we wanted to use the release 2.0.0 packages as dependencies.
This PR is for review purposes only, we still need to work out the final branching structure.
This is a port of Microsoft.Owin.Security.WsFederation. It targets Core 2.0 dependencies so that we can release it sooner than 2.1. As such some of the project files are unusual. We're also using the IdentityModel 5.2.0-preview1 dependencies from nuget.org. The version for this package will start as 2.0.0-alpha1.
The behavior is approximately the same as the Katana version, with minor updates to mirror those we made to OIDC when it was ported over. Changes:
options.SkipUnrecognizedRequests = true;to get some of the stranger legacy behavior apps have asked for in the past. OIDC uses the same mechanic.