Skip to content
This repository has been archived by the owner on Sep 18, 2021. It is now read-only.

Custom response parameters for custom grants #3137 #3139

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions source/Core/Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
<Compile Include="Events\TokenService\TokenIssuedDetailsBase.cs" />
<Compile Include="Events\Authentication\LocalLoginDetails.cs" />
<Compile Include="Extensions\CookieOptionsExtensions.cs" />
<Compile Include="Extensions\DictionaryExtensions.cs" />
<Compile Include="Extensions\HashExtensions.cs" />
<Compile Include="Extensions\IClientStoreExtensions.cs" />
<Compile Include="Extensions\IContainerExtensions.cs" />
Expand Down Expand Up @@ -248,6 +249,7 @@
<Compile Include="Services\IAuthenticationSessionValidator.cs" />
<Compile Include="Services\ICustomTokenResponseGenerator.cs" />
<Compile Include="Services\ISigningKeyService.cs" />
<Compile Include="Services\ObjectSerializer.cs" />
<Compile Include="Validation\BasicAuthenticationSecretParser.cs" />
<Compile Include="Validation\IntrospectionRequestValidationResult.cs" />
<Compile Include="Validation\IntrospectionRequestValidator.cs" />
Expand Down
6 changes: 3 additions & 3 deletions source/Core/Endpoints/Connect/TokenEndpointController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public async Task<IHttpActionResult> Post()
Logger.Info("Start token request");

var response = await ProcessAsync(await Request.GetOwinContext().ReadRequestFormAsNameValueCollectionAsync());

if (response is TokenErrorResult)
{
var details = response as TokenErrorResult;
Expand Down Expand Up @@ -106,11 +106,11 @@ public async Task<IHttpActionResult> ProcessAsync(NameValueCollection parameters

if (requestResult.IsError)
{
return this.TokenErrorResponse(requestResult.Error, requestResult.ErrorDescription);
return this.TokenErrorResponse(requestResult.Error, requestResult.ErrorDescription, requestResult.CustomResponseParamaters);
}

// return response
var response = await _generator.ProcessAsync(_requestValidator.ValidatedRequest);
var response = await _generator.ProcessAsync(_requestValidator.ValidatedRequest, requestResult.CustomResponseParamaters);
return this.TokenResponse(response);
}

Expand Down
31 changes: 31 additions & 0 deletions source/Core/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Newtonsoft.Json.Linq;

namespace IdentityServer3.Core.Extensions
{
internal static class DictionaryExtensions
{
public static void AddDictionary(this JObject jobject, IDictionary<string, object> dictionary)
{
foreach (var item in dictionary)
{
JToken token;
if (jobject.TryGetValue(item.Key, out token))
{
throw new Exception("Item does already exist - cannot add it via a custom entry: " + item.Key);
}

if (item.Value.GetType().GetTypeInfo().IsClass)
{
jobject.Add(new JProperty(item.Key, JToken.FromObject(item.Value)));
}
else
{
jobject.Add(new JProperty(item.Key, item.Value));
}
}
}
}
}
6 changes: 6 additions & 0 deletions source/Core/Extensions/ResultExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

using System.Collections.Generic;
using IdentityServer3.Core.Models;
using IdentityServer3.Core.Results;
using System.Web.Http;
Expand All @@ -36,5 +37,10 @@ public static IHttpActionResult TokenErrorResponse(this ApiController controller
{
return new TokenErrorResult(error, errorDescription);
}

public static IHttpActionResult TokenErrorResponse(this ApiController controller, string error, string errorDescription, IDictionary<string, object> customResponseParamaters)
{
return new TokenErrorResult(error, errorDescription, customResponseParamaters);
}
}
}
15 changes: 12 additions & 3 deletions source/Core/ResponseHandling/TokenResponseGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using IdentityServer3.Core.Services;
using IdentityServer3.Core.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -46,7 +47,7 @@ public TokenResponseGenerator(ITokenService tokenService, IRefreshTokenService r
_customResponseGenerator = customResponseGenerator;
}

public async Task<TokenResponse> ProcessAsync(ValidatedTokenRequest request)
public async Task<TokenResponse> ProcessAsync(ValidatedTokenRequest request, IDictionary<string, object> customResponseParameters = null)
{
Logger.Info("Creating token response");

Expand All @@ -65,6 +66,14 @@ public async Task<TokenResponse> ProcessAsync(ValidatedTokenRequest request)
response = await ProcessTokenRequestAsync(request);
}

if (customResponseParameters != null && customResponseParameters.Any())
{
foreach (var customResponseParameter in customResponseParameters)
{
response.Custom.Add(customResponseParameter.Key, customResponseParameter.Value);
}
}

return await _customResponseGenerator.GenerateAsync(request, response);
}

Expand Down Expand Up @@ -144,7 +153,7 @@ private async Task<TokenResponse> ProcessRefreshTokenRequestAsync(ValidatedToken

var oldAccessToken = request.RefreshToken.AccessToken;
string accessTokenString;

// if pop request, claims must be updated because we need a fresh proof token
if (request.Client.UpdateAccessTokenClaimsOnRefresh || request.RequestedTokenType == RequestedTokenTypes.PoP)
{
Expand Down Expand Up @@ -202,7 +211,7 @@ private async Task<Tuple<string, string>> CreateAccessTokenAsync(ValidatedTokenR
if (request.AuthorizationCode != null)
{
createRefreshToken = request.AuthorizationCode.RequestedScopes.Select(s => s.Name).Contains(Constants.StandardScopes.OfflineAccess);

tokenRequest = new TokenCreationRequest
{
Subject = request.AuthorizationCode.Subject,
Expand Down
37 changes: 32 additions & 5 deletions source/Core/Results/TokenErrorResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,53 @@
* limitations under the License.
*/

using System.Collections.Generic;
using System.Linq;
using IdentityServer3.Core.Logging;
using Newtonsoft.Json;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using IdentityServer3.Core.Extensions;
using IdentityServer3.Core.Services;

namespace IdentityServer3.Core.Results
{
internal class TokenErrorResult : IHttpActionResult
{
private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();

private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();

public IDictionary<string, object> CustomResponseParamaters { get; set; }
public string Error { get; internal set; }
public string ErrorDescription { get; internal set; }

public TokenErrorResult(string error)
{
Error = error;
CustomResponseParamaters = new Dictionary<string, object>();
}

public TokenErrorResult(string error, string errorDescription)
{
Error = error;
ErrorDescription = errorDescription;
CustomResponseParamaters = new Dictionary<string, object>();
}

public TokenErrorResult(string error, IDictionary<string, object> customResponseParamaters)
{
Error = error;
CustomResponseParamaters = customResponseParamaters;
}

public TokenErrorResult(string error, string errorDescription, IDictionary<string, object> customResponseParamaters)
{
Error = error;
ErrorDescription = errorDescription;
CustomResponseParamaters = customResponseParamaters;
}

public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
Expand All @@ -56,9 +76,16 @@ private HttpResponseMessage Execute()
error_description = ErrorDescription
};

var jObject = ObjectSerializer.ToJObject(dto);

if (CustomResponseParamaters != null && CustomResponseParamaters.Any())
{
jObject.AddDictionary(CustomResponseParamaters);
}

var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new ObjectContent<ErrorDto>(dto, new JsonMediaTypeFormatter())
Content = new StringContent(jObject.ToString(Formatting.None), Encoding.UTF8, "application/json")
};

Logger.Info("Returning error: " + Error);
Expand All @@ -70,6 +97,6 @@ internal class ErrorDto
public string error { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string error_description { get; set; }
}
}
}
}
36 changes: 8 additions & 28 deletions source/Core/Results/TokenResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,21 @@
using IdentityServer3.Core.Logging;
using IdentityServer3.Core.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using IdentityServer3.Core.Extensions;
using IdentityServer3.Core.Services;

namespace IdentityServer3.Core.Results
{
internal class TokenResult : IHttpActionResult
{
private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();
private readonly static JsonSerializer Serializer = new JsonSerializer
{
DefaultValueHandling = DefaultValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};
private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();

private readonly TokenResponse _response;

Expand All @@ -62,33 +57,18 @@ private HttpResponseMessage Execute()
alg = _response.Algorithm
};

var jobject = JObject.FromObject(dto, Serializer);
var jObject = ObjectSerializer.ToJObject(dto);

// custom entries
if (_response.Custom != null && _response.Custom.Any())
{
foreach (var item in _response.Custom)
{
JToken token;
if (jobject.TryGetValue(item.Key, out token))
{
throw new Exception("Item does already exist - cannot add it via a custom entry: " + item.Key);
}

if (item.Value.GetType().IsClass)
{
jobject.Add(new JProperty(item.Key, JToken.FromObject(item.Value)));
}
else
{
jobject.Add(new JProperty(item.Key, item.Value));
}
}
jObject.AddDictionary(_response.Custom);
}

var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(jobject.ToString(Formatting.None), Encoding.UTF8, "application/json")
//Content = new ObjectContent<JObject>(jobject, new JsonMediaTypeFormatter())
Content = new StringContent(jObject.ToString(Formatting.None), Encoding.UTF8, "application/json")
};

Logger.Info("Returning token response.");
Expand All @@ -103,6 +83,6 @@ internal class TokenResponseDto
public string token_type { get; set; }
public string refresh_token { get; set; }
public string alg { get; set; }
}
}
}
}
Loading