Skip to content
This repository was archived by the owner on Dec 24, 2020. It is now read-only.

Commit 3b9dd31

Browse files
committed
Update the introspection middleware to encrypt authentication tickets before storing them in the distributed cache
1 parent 24f4a3a commit 3b9dd31

File tree

7 files changed

+78
-11
lines changed

7 files changed

+78
-11
lines changed

src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ protected virtual Task<AuthenticationTicket> CreateTicketAsync(JObject payload)
292292
}
293293

294294
protected virtual Task StoreTicketAsync(string token, AuthenticationTicket ticket) {
295-
var bytes = Options.TicketSerializer.Serialize(ticket);
295+
var bytes = Encoding.UTF8.GetBytes(Options.AccessTokenFormat.Protect(ticket));
296296
Debug.Assert(bytes != null);
297297

298298
return Options.Cache.SetAsync(token, bytes, new DistributedCacheEntryOptions {
@@ -308,7 +308,7 @@ protected virtual async Task<AuthenticationTicket> RetrieveTicketAsync(string to
308308
return null;
309309
}
310310

311-
return Options.TicketSerializer.Deserialize(bytes);
311+
return Options.AccessTokenFormat.Unprotect(Encoding.UTF8.GetString(bytes));
312312
}
313313
}
314314
}

src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionMiddleware.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Text.Encodings.Web;
1010
using JetBrains.Annotations;
1111
using Microsoft.AspNetCore.Authentication;
12+
using Microsoft.AspNetCore.DataProtection;
1213
using Microsoft.AspNetCore.Http;
1314
using Microsoft.Extensions.Caching.Distributed;
1415
using Microsoft.Extensions.Logging;
@@ -21,7 +22,8 @@ public OAuthIntrospectionMiddleware(
2122
[NotNull] IOptions<OAuthIntrospectionOptions> options,
2223
[NotNull] ILoggerFactory loggerFactory,
2324
[NotNull] UrlEncoder encoder,
24-
[NotNull] IDistributedCache cache)
25+
[NotNull] IDistributedCache cache,
26+
[NotNull] IDataProtectionProvider dataProtectionProvider)
2527
: base(next, options, loggerFactory, encoder) {
2628
if (string.IsNullOrEmpty(Options.Authority) &&
2729
string.IsNullOrEmpty(Options.IntrospectionEndpoint)) {
@@ -33,6 +35,18 @@ public OAuthIntrospectionMiddleware(
3335
throw new ArgumentException("Client credentials must be configured.", nameof(options));
3436
}
3537

38+
if (Options.DataProtectionProvider == null) {
39+
Options.DataProtectionProvider = dataProtectionProvider;
40+
}
41+
42+
if (Options.AccessTokenFormat == null) {
43+
var protector = Options.DataProtectionProvider.CreateProtector(
44+
nameof(OAuthIntrospectionMiddleware),
45+
Options.AuthenticationScheme, "Access_Token", "v1");
46+
47+
Options.AccessTokenFormat = new TicketDataFormat(protector);
48+
}
49+
3650
if (Options.Cache == null) {
3751
Options.Cache = cache;
3852
}

src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionOptions.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Net.Http;
99
using Microsoft.AspNetCore.Authentication;
1010
using Microsoft.AspNetCore.Builder;
11+
using Microsoft.AspNetCore.DataProtection;
1112
using Microsoft.Extensions.Caching.Distributed;
1213

1314
namespace AspNet.Security.OAuth.Introspection {
@@ -62,9 +63,17 @@ public OAuthIntrospectionOptions() {
6263
public ISystemClock SystemClock { get; set; } = new SystemClock();
6364

6465
/// <summary>
65-
/// Gets or sets the serializer used to serialize and deserialize
66+
/// Gets or sets the data format used to serialize and deserialize
6667
/// the authenticated tickets stored in the distributed cache.
6768
/// </summary>
68-
public IDataSerializer<AuthenticationTicket> TicketSerializer { get; set; } = new TicketSerializer();
69+
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; set; }
70+
71+
/// <summary>
72+
/// Gets or sets the data protection provider used to create the default
73+
/// data protectors used by <see cref="OAuthIntrospectionMiddleware"/>.
74+
/// When this property is set to <c>null</c>, the data protection provider
75+
/// is directly retrieved from the dependency injection container.
76+
/// </summary>
77+
public IDataProtectionProvider DataProtectionProvider { get; set; }
6978
}
7079
}

src/Owin.Security.OAuth.Introspection/OAuthIntrospectionHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ protected virtual Task<AuthenticationTicket> CreateTicketAsync(JObject payload)
286286
}
287287

288288
protected virtual Task StoreTicketAsync(string token, AuthenticationTicket ticket) {
289-
var bytes = Options.TicketSerializer.Serialize(ticket);
289+
var bytes = Encoding.UTF8.GetBytes(Options.AccessTokenFormat.Protect(ticket));
290290
Debug.Assert(bytes != null);
291291

292292
return Options.Cache.SetAsync(token, bytes, new DistributedCacheEntryOptions {
@@ -302,7 +302,7 @@ protected virtual async Task<AuthenticationTicket> RetrieveTicketAsync(string to
302302
return null;
303303
}
304304

305-
return Options.TicketSerializer.Deserialize(bytes);
305+
return Options.AccessTokenFormat.Unprotect(Encoding.UTF8.GetString(bytes));
306306
}
307307
}
308308
}

src/Owin.Security.OAuth.Introspection/OAuthIntrospectionMiddleware.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
using System;
88
using System.Net.Http;
99
using JetBrains.Annotations;
10+
using Microsoft.AspNetCore.DataProtection;
1011
using Microsoft.Extensions.Caching.Distributed;
1112
using Microsoft.Extensions.Caching.Memory;
13+
using Microsoft.Extensions.DependencyInjection;
1214
using Microsoft.Extensions.Logging;
1315
using Microsoft.Owin;
16+
using Microsoft.Owin.BuilderProperties;
1417
using Microsoft.Owin.Security.Infrastructure;
18+
using Microsoft.Owin.Security.Interop;
1519

1620
namespace Owin.Security.OAuth.Introspection {
1721
public class OAuthIntrospectionMiddleware : AuthenticationMiddleware<OAuthIntrospectionOptions> {
@@ -30,6 +34,39 @@ public OAuthIntrospectionMiddleware(
3034
throw new ArgumentException("Client credentials must be configured.", nameof(options));
3135
}
3236

37+
if (options.DataProtectionProvider == null) {
38+
// Create a new DI container and register
39+
// the data protection services.
40+
var services = new ServiceCollection();
41+
42+
services.AddDataProtection(configuration => {
43+
// Try to use the application name provided by
44+
// the OWIN host as the application discriminator.
45+
var discriminator = new AppProperties(app.Properties).AppName;
46+
47+
// When an application discriminator cannot be resolved from
48+
// the OWIN host properties, generate a temporary identifier.
49+
if (string.IsNullOrEmpty(discriminator)) {
50+
discriminator = Guid.NewGuid().ToString();
51+
}
52+
53+
configuration.ApplicationDiscriminator = discriminator;
54+
});
55+
56+
var container = services.BuildServiceProvider();
57+
58+
// Resolve a data protection provider from the services container.
59+
options.DataProtectionProvider = container.GetRequiredService<IDataProtectionProvider>();
60+
}
61+
62+
if (options.AccessTokenFormat == null) {
63+
var protector = Options.DataProtectionProvider.CreateProtector(
64+
nameof(OAuthIntrospectionMiddleware),
65+
Options.AuthenticationType, "Access_Token", "v1");
66+
67+
options.AccessTokenFormat = new AspNetTicketDataFormat(new DataProtectorShim(protector));
68+
}
69+
3370
if (options.Cache == null) {
3471
options.Cache = new MemoryDistributedCache(new MemoryCache(new MemoryCacheOptions {
3572
CompactOnMemoryPressure = true

src/Owin.Security.OAuth.Introspection/OAuthIntrospectionOptions.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
using System.Collections.Generic;
88
using System.Net.Http;
9+
using Microsoft.AspNetCore.DataProtection;
910
using Microsoft.Extensions.Caching.Distributed;
1011
using Microsoft.Extensions.Logging;
1112
using Microsoft.Owin.Infrastructure;
1213
using Microsoft.Owin.Security;
13-
using Microsoft.Owin.Security.DataHandler.Serializer;
1414

1515
namespace Owin.Security.OAuth.Introspection {
1616
public class OAuthIntrospectionOptions : AuthenticationOptions {
@@ -70,9 +70,15 @@ public OAuthIntrospectionOptions()
7070
public ISystemClock SystemClock { get; set; } = new SystemClock();
7171

7272
/// <summary>
73-
/// Gets or sets the serializer used to serialize and deserialize
73+
/// Gets or sets the data format used to serialize and deserialize
7474
/// the authenticated tickets stored in the distributed cache.
7575
/// </summary>
76-
public IDataSerializer<AuthenticationTicket> TicketSerializer { get; set; } = new TicketSerializer();
76+
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; set; }
77+
78+
/// <summary>
79+
/// Gets or sets the data protection provider used to create the default
80+
/// data protectors used by <see cref="OAuthIntrospectionMiddleware"/>.
81+
/// </summary>
82+
public IDataProtectionProvider DataProtectionProvider { get; set; }
7783
}
7884
}

src/Owin.Security.OAuth.Introspection/project.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@
3131
"JetBrains.Annotations": { "type": "build", "version": "10.1.2-eap" },
3232
"Microsoft.Extensions.Caching.Memory": "1.0.0-*",
3333
"Microsoft.Extensions.Logging": "1.0.0-*",
34-
"Microsoft.Owin.Security": "3.0.1",
34+
"Microsoft.Owin.Security.Interop": "1.0.0-*",
3535
"Newtonsoft.Json": "8.0.3"
3636
},
3737

3838
"frameworks": {
3939
"net451": {
4040
"frameworkAssemblies": {
41+
"System.ComponentModel": { "type": "build" },
4142
"System.Net.Http": "4.0.0.0",
4243
"System.Runtime": { "type": "build" },
4344
"System.Threading.Tasks": { "type": "build" }

0 commit comments

Comments
 (0)