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

Commit

Permalink
Merge pull request #2382 from IdentityServer/CustomTokenResponseGener…
Browse files Browse the repository at this point in the history
…ator

Added new service for adding custom entries to a token response
  • Loading branch information
leastprivilege committed Jan 24, 2016
2 parents 09057ae + 89e7577 commit d7afa1e
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 21 deletions.
1 change: 1 addition & 0 deletions source/Core/Configuration/Hosting/AutoFacConfig.cs
Expand Up @@ -67,6 +67,7 @@ public static IContainer Configure(IdentityServerOptions options)
builder.RegisterDefaultType<ICustomRequestValidator, DefaultCustomRequestValidator>(fact.CustomRequestValidator);
builder.RegisterDefaultType<IExternalClaimsFilter, NopClaimsFilter>(fact.ExternalClaimsFilter);
builder.RegisterDefaultType<ICustomTokenValidator, DefaultCustomTokenValidator>(fact.CustomTokenValidator);
builder.RegisterDefaultType<ICustomTokenResponseGenerator, DefaultCustomTokenResponseGenerator>(fact.CustomTokenResponseGenerator);
builder.RegisterDefaultType<IConsentService, DefaultConsentService>(fact.ConsentService);
builder.RegisterDefaultType<IAuthenticationSessionValidator, DefaultAuthenticationSessionValidator>(fact.AuthenticationSessionValidator);

Expand Down
7 changes: 7 additions & 0 deletions source/Core/Configuration/IdentityServerServiceFactory.cs
Expand Up @@ -307,6 +307,13 @@ public void Register<T>(Registration<T> registration)
/// </value>
public Registration<ICorsPolicyService> CorsPolicyService { get; set; }

/// Gets or sets the custom token response generator
/// </summary>
/// <value>
/// The custom token response generator
/// </value>
public Registration<ICustomTokenResponseGenerator> CustomTokenResponseGenerator { get; set; }

/// <summary>
/// Gets or sets the authentication session validator.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions source/Core/Core.csproj
Expand Up @@ -237,9 +237,11 @@
<Compile Include="Services\DefaultViewService\DefaultViewServiceOptions.cs" />
<Compile Include="Services\DefaultViewService\DefaultViewServiceRegistration.cs" />
<Compile Include="Services\Default\DefaultAuthenticationSessionValidator.cs" />
<Compile Include="Services\Default\DefaultCustomTokenResponseGenerator.cs" />
<Compile Include="Services\Default\DefaultSigningKeyService.cs" />
<Compile Include="Services\Default\DefaultTokenSigningService.cs" />
<Compile Include="Services\IAuthenticationSessionValidator.cs" />
<Compile Include="Services\ICustomTokenResponseGenerator.cs" />
<Compile Include="Services\ISigningKeyService.cs" />
<Compile Include="Validation\BasicAuthenticationSecretParser.cs" />
<Compile Include="Validation\IntrospectionRequestValidationResult.cs" />
Expand Down
10 changes: 9 additions & 1 deletion source/Core/Models/TokenResponse.cs
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

using System.Collections.Generic;
using System.ComponentModel;

#pragma warning disable 1591
Expand All @@ -27,5 +28,12 @@ public class TokenResponse
public string AccessToken { get; set; }
public int AccessTokenLifetime { get; set; }
public string RefreshToken { get; set; }

public Dictionary<string, object> Custom { get; set; }

public TokenResponse()
{
Custom = new Dictionary<string, object>();
}
}
}
}
21 changes: 14 additions & 7 deletions source/Core/ResponseHandling/TokenResponseGenerator.cs
Expand Up @@ -36,29 +36,36 @@ public class TokenResponseGenerator
private readonly ITokenService _tokenService;
private readonly IRefreshTokenService _refreshTokenService;
private readonly IScopeStore _scopes;

public TokenResponseGenerator(ITokenService tokenService, IRefreshTokenService refreshTokenService, IScopeStore scopes)
private readonly ICustomTokenResponseGenerator _customResponseGenerator;

public TokenResponseGenerator(ITokenService tokenService, IRefreshTokenService refreshTokenService, IScopeStore scopes, ICustomTokenResponseGenerator customResponseGenerator)
{
_tokenService = tokenService;
_refreshTokenService = refreshTokenService;
_scopes = scopes;
_customResponseGenerator = customResponseGenerator;
}

public async Task<TokenResponse> ProcessAsync(ValidatedTokenRequest request)
{
Logger.Info("Creating token response");

TokenResponse response;

if (request.GrantType == Constants.GrantTypes.AuthorizationCode)
{
return await ProcessAuthorizationCodeRequestAsync(request);
response = await ProcessAuthorizationCodeRequestAsync(request);
}

if (request.GrantType == Constants.GrantTypes.RefreshToken)
else if (request.GrantType == Constants.GrantTypes.RefreshToken)
{
response = await ProcessRefreshTokenRequestAsync(request);
}
else
{
return await ProcessRefreshTokenRequestAsync(request);
response = await ProcessTokenRequestAsync(request);
}

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

private async Task<TokenResponse> ProcessAuthorizationCodeRequestAsync(ValidatedTokenRequest request)
Expand Down
31 changes: 27 additions & 4 deletions source/Core/Results/TokenResult.cs
Expand Up @@ -17,9 +17,13 @@
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.Net.Http.Formatting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
Expand All @@ -29,11 +33,12 @@ namespace IdentityServer3.Core.Results
internal class TokenResult : IHttpActionResult
{
private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();
private readonly static JsonMediaTypeFormatter Formatter = new JsonMediaTypeFormatter
private readonly static JsonSerializer Serializer = new JsonSerializer
{
SerializerSettings = { DefaultValueHandling = DefaultValueHandling.Ignore }
DefaultValueHandling = DefaultValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};

private readonly TokenResponse _response;

public TokenResult(TokenResponse response)
Expand All @@ -57,9 +62,27 @@ private HttpResponseMessage Execute()
token_type = Constants.TokenTypes.Bearer
};

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

// 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);
}

jobject.Add(new JProperty(item.Key, item.Value));
}
}

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

Logger.Info("Returning token response.");
Expand Down
@@ -0,0 +1,23 @@
using IdentityServer3.Core.Models;
using IdentityServer3.Core.Validation;
using System.Threading.Tasks;

namespace IdentityServer3.Core.Services.Default
{
/// <summary>
/// nop custom token response generator
/// </summary>
public class DefaultCustomTokenResponseGenerator : ICustomTokenResponseGenerator
{
/// <summary>
/// Custom response generation
/// </summary>
/// <param name="request">The validated request.</param>
/// <param name="response">The standard token response.</param>
/// <returns>The custom token response.</returns>
public Task<TokenResponse> GenerateAsync(ValidatedTokenRequest request, TokenResponse response)
{
return Task.FromResult(response);
}
}
}
36 changes: 36 additions & 0 deletions source/Core/Services/ICustomTokenResponseGenerator.cs
@@ -0,0 +1,36 @@
/*
* Copyright 2014, 2015 Dominick Baier, Brock Allen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using IdentityServer3.Core.Models;
using IdentityServer3.Core.Validation;
using System.Threading.Tasks;

namespace IdentityServer3.Core.Services
{
/// <summary>
/// Allows adding custom data to a token response
/// </summary>
public interface ICustomTokenResponseGenerator
{
/// <summary>
/// Custom response generation
/// </summary>
/// <param name="request">The validated request.</param>
/// <param name="response">The standard token response.</param>
/// <returns>The custom token response.</returns>
Task<TokenResponse> GenerateAsync(ValidatedTokenRequest request, TokenResponse response);
}
}
Expand Up @@ -18,7 +18,7 @@
using IdentityServer3.Core.Validation;
using System.Threading.Tasks;

namespace IdentityServer3.Host.Config
namespace Host.Configuration.Extensions
{
public class AnotherCustomGrantValidator : ICustomGrantValidator
{
Expand Down
Expand Up @@ -18,7 +18,7 @@
using IdentityServer3.Core.Validation;
using System.Threading.Tasks;

namespace IdentityServer3.Host.Config
namespace Host.Configuration.Extensions
{
public class CustomGrantValidator : ICustomGrantValidator
{
Expand Down
@@ -0,0 +1,17 @@
using IdentityServer3.Core.Models;
using IdentityServer3.Core.Services;
using IdentityServer3.Core.Validation;
using System.Threading.Tasks;

namespace Host.Configuration.Extensions
{
class CustomTokenResponseGenerator : ICustomTokenResponseGenerator
{
public Task<TokenResponse> GenerateAsync(ValidatedTokenRequest request, TokenResponse response)
{
response.Custom.Add("custom_field", "custom data");

return Task.FromResult(response);
}
}
}
19 changes: 14 additions & 5 deletions source/Host.Configuration/FactoryExtensions.cs
@@ -1,16 +1,25 @@
using IdentityServer3.Core.Services;
using IdentityServer3.Host.Config;
using Host.Configuration.Extensions;
using IdentityServer3.Core.Configuration;
using IdentityServer3.Core.Services;

namespace IdentityServer3.Core.Configuration
namespace Host.Configuration
{
static class FactoryExtensions
{
public static IdentityServerServiceFactory AddCustomGrantValidators(this IdentityServerServiceFactory factory)
{
factory.CustomGrantValidators.Add(
new Registration<ICustomGrantValidator>(typeof(CustomGrantValidator)));
new Registration<ICustomGrantValidator, CustomGrantValidator>());
factory.CustomGrantValidators.Add(
new Registration<ICustomGrantValidator>(typeof(AnotherCustomGrantValidator)));
new Registration<ICustomGrantValidator, AnotherCustomGrantValidator>());

return factory;
}

public static IdentityServerServiceFactory AddCustomTokenResponseGenerator(this IdentityServerServiceFactory factory)
{
factory.CustomTokenResponseGenerator =
new Registration<ICustomTokenResponseGenerator, CustomTokenResponseGenerator>();

return factory;
}
Expand Down
5 changes: 3 additions & 2 deletions source/Host.Configuration/Host.Configuration.csproj
Expand Up @@ -88,12 +88,13 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Config\AnotherCustomGrantValidator.cs" />
<Compile Include="Extensions\AnotherCustomGrantValidator.cs" />
<Compile Include="Config\Cert.cs" />
<Compile Include="Config\Clients.cs" />
<Compile Include="Config\CustomGrantValidator.cs" />
<Compile Include="Extensions\CustomGrantValidator.cs" />
<Compile Include="Config\Scopes.cs" />
<Compile Include="Config\Users.cs" />
<Compile Include="Extensions\CustomTokenResponseGenerator.cs" />
<Compile Include="FactoryExtensions.cs" />
<Compile Include="IdentityServerExtension.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
2 changes: 2 additions & 0 deletions source/Host.Configuration/IdentityServerExtension.cs
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

using Host.Configuration;
using IdentityServer3.Core.Configuration;
using IdentityServer3.Host.Config;
using Microsoft.Owin;
Expand Down Expand Up @@ -41,6 +42,7 @@ public static IAppBuilder UseIdentityServer(this IAppBuilder app)
.UseInMemoryScopes(Scopes.Get());
factory.AddCustomGrantValidators();
factory.AddCustomTokenResponseGenerator();
factory.ConfigureClientStoreCache();
factory.ConfigureScopeStoreCache();
Expand Down

0 comments on commit d7afa1e

Please sign in to comment.