diff --git a/samples/OpenIdConnectSample/Properties/launchSettings.json b/samples/OpenIdConnectSample/Properties/launchSettings.json
index d8622657cf..a744c05c54 100644
--- a/samples/OpenIdConnectSample/Properties/launchSettings.json
+++ b/samples/OpenIdConnectSample/Properties/launchSettings.json
@@ -10,12 +10,12 @@
"kestrel": {
"commandName": "kestrel",
"launchBrowser": true,
- "launchUrl": "http://localhost:5004"
+ "launchUrl": "http://localhost:42023"
},
"web": {
"commandName": "web",
"launchBrowser": true,
- "launchUrl": "http://localhost:12345"
+ "launchUrl": "http://localhost:42023"
}
}
}
\ No newline at end of file
diff --git a/samples/OpenIdConnectSample/Startup.cs b/samples/OpenIdConnectSample/Startup.cs
index 3a0a289e72..177e866d7b 100644
--- a/samples/OpenIdConnectSample/Startup.cs
+++ b/samples/OpenIdConnectSample/Startup.cs
@@ -6,6 +6,7 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
+using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace OpenIdConnectSample
{
@@ -28,8 +29,10 @@ namespace OpenIdConnectSample
app.UseOpenIdConnectAuthentication(options =>
{
options.ClientId = "63a87a83-64b9-4ac1-b2c5-092126f8474f";
+ options.ClientSecret = "Yse2iP7tO1Azq0iDajNisMaTSnIDv+FXmAsFuXr+Cy8="; // for code flow
options.Authority = "https://login.windows.net/tratcheroutlook.onmicrosoft.com";
options.RedirectUri = "http://localhost:42023";
+ options.ResponseType = OpenIdConnectResponseTypes.Code;
});
app.Run(async context =>
diff --git a/samples/OpenIdConnectSample/project.json b/samples/OpenIdConnectSample/project.json
index ad9c36c6f7..2dbf30c6bd 100644
--- a/samples/OpenIdConnectSample/project.json
+++ b/samples/OpenIdConnectSample/project.json
@@ -13,8 +13,8 @@
"dnxcore50": { }
},
"commands": {
- "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:12345",
- "kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5004"
+ "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:42023",
+ "kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:42023"
},
"webroot": "wwwroot"
}
diff --git a/src/Microsoft.AspNet.Authentication.JwtBearer/project.json b/src/Microsoft.AspNet.Authentication.JwtBearer/project.json
index f05599e083..722ed90f88 100644
--- a/src/Microsoft.AspNet.Authentication.JwtBearer/project.json
+++ b/src/Microsoft.AspNet.Authentication.JwtBearer/project.json
@@ -8,7 +8,7 @@
"dependencies": {
"Microsoft.AspNet.Authentication": "1.0.0-*",
"Microsoft.Framework.NotNullAttribute.Sources": { "type": "build", "version": "1.0.0-*" },
- "Microsoft.IdentityModel.Protocols.OpenIdConnect": "2.0.0-beta7-*"
+ "Microsoft.IdentityModel.Protocols.OpenIdConnect": "2.0.0-beta8-*"
},
"frameworks": {
"dnx451": {
diff --git a/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectHandler.cs b/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectHandler.cs
index ea5f844bac..1c044332cc 100644
--- a/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectHandler.cs
+++ b/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectHandler.cs
@@ -320,7 +320,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
// response_mode=query (explicit or not) and a response_type containing id_token
// or token are not considered as a safe combination and MUST be rejected.
// See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security
- if (!string.IsNullOrEmpty(message.IdToken) || !string.IsNullOrEmpty(message.Token))
+ if (!string.IsNullOrEmpty(message.IdToken) || !string.IsNullOrEmpty(message.AccessToken))
{
Logger.LogError("An OpenID Connect response cannot contain an identity token " +
"or an access token when using response_mode=query");
@@ -359,7 +359,8 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
// Fail if state is missing, it's required for the correlation id.
if (string.IsNullOrEmpty(message.State))
{
- Logger.LogError(Resources.OIDCH_0004_MessageStateIsNullOrEmpty);
+ // This wasn't a valid ODIC message, it may not have been intended for us.
+ Logger.LogVerbose(Resources.OIDCH_0004_MessageStateIsNullOrEmpty);
return null;
}
@@ -462,6 +463,12 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
AuthenticationTicket ticket = null;
JwtSecurityToken jwt = null;
+ Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext()
+ {
+ ClientId = Options.ClientId,
+ ProtocolMessage = message,
+ });
+
var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(message, properties, ticket, jwt);
if (authorizationCodeReceivedContext.HandledResponse)
{
@@ -498,7 +505,19 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
ticket = ValidateToken(tokenEndpointResponse.ProtocolMessage.IdToken, message, properties, validationParameters, out jwt);
- ValidateOpenIdConnectProtocol(null, message);
+ var nonce = jwt?.Payload.Nonce;
+ if (!string.IsNullOrEmpty(nonce))
+ {
+ nonce = ReadNonceCookie(nonce);
+ }
+
+ Options.ProtocolValidator.ValidateTokenResponse(new OpenIdConnectProtocolValidationContext()
+ {
+ ClientId = Options.ClientId,
+ ProtocolMessage = tokenEndpointResponse.ProtocolMessage,
+ ValidatedIdToken = jwt,
+ Nonce = nonce
+ });
var authenticationValidatedContext = await RunAuthenticationValidatedEventAsync(message, ticket, tokenEndpointResponse);
if (authenticationValidatedContext.HandledResponse)
@@ -520,7 +539,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
if (Options.GetClaimsFromUserInfoEndpoint)
{
Logger.LogDebug(Resources.OIDCH_0040_Sending_Request_UIEndpoint);
- ticket = await GetUserInformationAsync(tokenEndpointResponse.ProtocolMessage, ticket);
+ ticket = await GetUserInformationAsync(tokenEndpointResponse.ProtocolMessage, jwt, ticket);
}
return ticket;
@@ -535,7 +554,19 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
var validationParameters = Options.TokenValidationParameters.Clone();
var ticket = ValidateToken(message.IdToken, message, properties, validationParameters, out jwt);
- ValidateOpenIdConnectProtocol(jwt, message);
+ var nonce = jwt?.Payload.Nonce;
+ if (!string.IsNullOrEmpty(nonce))
+ {
+ nonce = ReadNonceCookie(nonce);
+ }
+
+ Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext()
+ {
+ ClientId = Options.ClientId,
+ ProtocolMessage = message,
+ ValidatedIdToken = jwt,
+ Nonce = nonce
+ });
var authenticationValidatedContext = await RunAuthenticationValidatedEventAsync(message, ticket, tokenEndpointResponse: null);
if (authenticationValidatedContext.HandledResponse)
@@ -619,7 +650,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
/// message that is being processed
/// authentication ticket with claims principal and identities
/// Authentication ticket with identity with additional claims, if any.
- protected virtual async Task GetUserInformationAsync(OpenIdConnectMessage message, AuthenticationTicket ticket)
+ protected virtual async Task GetUserInformationAsync(OpenIdConnectMessage message, JwtSecurityToken jwt, AuthenticationTicket ticket)
{
var userInfoEndpoint = _configuration?.UserInfoEndpoint;
@@ -634,6 +665,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
var responseMessage = await Backchannel.SendAsync(requestMessage);
responseMessage.EnsureSuccessStatusCode();
var userInfoResponse = await responseMessage.Content.ReadAsStringAsync();
+ var userInfoEndpointJwt = new JwtSecurityToken(userInfoResponse);
var user = JObject.Parse(userInfoResponse);
var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(ticket, message, user);
@@ -648,20 +680,13 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
ticket = userInformationReceivedContext.AuthenticationTicket;
user = userInformationReceivedContext.User;
+ Options.ProtocolValidator.ValidateUserInfoResponse(new OpenIdConnectProtocolValidationContext()
+ {
+ UserInfoEndpointResponse = userInfoEndpointJwt,
+ ValidatedIdToken = jwt,
+ });
+
var identity = (ClaimsIdentity)ticket.Principal.Identity;
- var subjectClaimType = identity.FindFirst(ClaimTypes.NameIdentifier);
- if (subjectClaimType == null)
- {
- throw new OpenIdConnectProtocolException(string.Format(CultureInfo.InvariantCulture, Resources.OIDCH_0041_Subject_Claim_Not_Found, identity.ToString()));
- }
-
- var userInfoSubjectClaimValue = user.Value(JwtRegisteredClaimNames.Sub);
-
- // check if the sub claim matches
- if (userInfoSubjectClaimValue == null || !string.Equals(userInfoSubjectClaimValue, subjectClaimType.Value, StringComparison.Ordinal))
- {
- throw new OpenIdConnectProtocolException(Resources.OIDCH_0039_Subject_Claim_Mismatch);
- }
foreach (var claim in identity.Claims)
{
@@ -1097,25 +1122,6 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
return ticket;
}
- private void ValidateOpenIdConnectProtocol(JwtSecurityToken jwt, OpenIdConnectMessage message)
- {
- string nonce = jwt?.Payload.Nonce;
- if (!string.IsNullOrEmpty(nonce))
- {
- nonce = ReadNonceCookie(nonce);
- }
-
- var protocolValidationContext = new OpenIdConnectProtocolValidationContext
- {
- ProtocolMessage = message,
- IdToken = jwt,
- ClientId = Options.ClientId,
- Nonce = nonce
- };
-
- Options.ProtocolValidator.Validate(protocolValidationContext);
- }
-
///
/// Calls InvokeReplyPathAsync
///
diff --git a/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectOptions.cs b/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectOptions.cs
index fedc2db7be..aa77d09040 100644
--- a/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectOptions.cs
+++ b/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectOptions.cs
@@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
/// if 'value' is null.
public OpenIdConnectProtocolValidator ProtocolValidator { get; set; } = new OpenIdConnectProtocolValidator()
{
- RequireState = false,
+ RequireStateValidation = false,
NonceLifetime = TimeSpan.FromMinutes(15)
};
diff --git a/src/Microsoft.AspNet.Authentication.OpenIdConnect/project.json b/src/Microsoft.AspNet.Authentication.OpenIdConnect/project.json
index c81a8d085b..15fe781773 100644
--- a/src/Microsoft.AspNet.Authentication.OpenIdConnect/project.json
+++ b/src/Microsoft.AspNet.Authentication.OpenIdConnect/project.json
@@ -8,7 +8,7 @@
"dependencies": {
"Microsoft.AspNet.Authentication": "1.0.0-*",
"Microsoft.Framework.NotNullAttribute.Sources": { "type": "build", "version": "1.0.0-*" },
- "Microsoft.IdentityModel.Protocols.OpenIdConnect": "2.0.0-beta7-*"
+ "Microsoft.IdentityModel.Protocols.OpenIdConnect": "2.0.0-beta8-*"
},
"frameworks": {
"dnx451": {
diff --git a/test/Microsoft.AspNet.Authentication.Test/OpenIdConnect/OpenIdConnectHandlerForTestingAuthenticate.cs b/test/Microsoft.AspNet.Authentication.Test/OpenIdConnect/OpenIdConnectHandlerForTestingAuthenticate.cs
index f9cd88d57e..79e96d7d1c 100644
--- a/test/Microsoft.AspNet.Authentication.Test/OpenIdConnect/OpenIdConnectHandlerForTestingAuthenticate.cs
+++ b/test/Microsoft.AspNet.Authentication.Test/OpenIdConnect/OpenIdConnectHandlerForTestingAuthenticate.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Authentication.OpenIdConnect;
@@ -33,7 +34,7 @@ namespace Microsoft.AspNet.Authentication.Tests.OpenIdConnect
return Task.FromResult(new OpenIdConnectTokenEndpointResponse(jsonResponse));
}
- protected override Task GetUserInformationAsync(OpenIdConnectMessage message, AuthenticationTicket ticket)
+ protected override Task GetUserInformationAsync(OpenIdConnectMessage message, JwtSecurityToken jwt, AuthenticationTicket ticket)
{
var claimsIdentity = (ClaimsIdentity)ticket.Principal.Identity;
if (claimsIdentity == null)