Skip to content

Commit c9eaaa0

Browse files
Merge pull request #72 from mdsol/develop
Release of v5.1.1
2 parents 843701f + 87ba132 commit c9eaaa0

35 files changed

+815
-218
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*.user
77
*.userosscache
88
*.sln.docstates
9+
.vscode/
910

1011
# User-specific files (MonoDevelop/Xamarin Studio)
1112
*.userprefs
@@ -139,7 +140,7 @@ publish/
139140
*.[Pp]ublish.xml
140141
*.azurePubxml
141142

142-
# TODO: Un-comment the next line if you do not want to checkin
143+
# TODO: Un-comment the next line if you do not want to checkin
143144
# your web deploy settings because they may include unencrypted
144145
# passwords
145146
#*.pubxml

CHANGELOG.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changes in Medidata.MAuth
22

3+
## v5.1.1
4+
- **[Core]** Fixed an issue with internal caching for the utility extension `Authenticate()` method.
5+
6+
## v5.1.0
7+
- **[Core]** Added multi-target for .NET 5 to support synchronus HttpClient requests.
8+
- **[Core]** Updated MAuthSigningHandler to sign synchronus requests.
9+
- **[Core]** Updated MAuthAuthenticator to create and reuse a single HttpClient instead of creating a new one for each MAuthRequestRetrier.
10+
- **[Core]** Updated MAuthAuthenticator to limit the calls to the cache item factory method to a single thread per key not already in the cache.
11+
12+
## v5.0.1
13+
- **[Core]** Inflate private key upon set in options classes.
14+
315
## v5.0.0
416
- **[Core]** Added normalization of Uri AbsolutePath.
517
- **[Core]** Added unescape step in query_string encoding to remove `double encoding`.
@@ -45,7 +57,7 @@ provided options.
4557
- **[Core]** Removed constraint for the application uuids to be only version 4. Now the MAuth header validation won't throw error if the provided uuid is not version 4.
4658

4759
## v3.0.0
48-
- **[All]** **Breaking** - Changed the HTTP status code response in case of any errors (including authentication and validation errors) from Forbidden (403) to Unauthorized (401).
60+
- **[All]** **Breaking** - Changed the HTTP status code response in case of any errors (including authentication and validation errors) from Forbidden (403) to Unauthorized (401).
4961
`HideExceptionsAndReturnForbidden` property of MAuth option class has also been renamed to `HideExceptionsAndReturnUnauthorized`.
5062

5163
## v2.4.1
@@ -86,7 +98,7 @@ downloads and referencing from NuGet
8698
## v2.0.0
8799
- **[Core]** The `MAuthSigningHandler` is accepting an `MAuthSigningOptions` instance instead of
88100
an `MAuthOptions` instance (which in turn set to be an abstract class)
89-
- [**Owin]** The OWIN middleware infrastructure provided request body stream gets replaced
101+
- [**Owin]** The OWIN middleware infrastructure provided request body stream gets replaced
90102
with a `MemoryStream` in cases when the original body stream is not seekable.
91103

92104
## v1.0.0

Directory.Build.props

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<Project>
4+
<Import Project="version.props"/>
5+
6+
<PropertyGroup>
7+
<LangVersion>latest</LangVersion>
8+
<Nullable>disable</Nullable>
9+
<NoPackageAnalysis>true</NoPackageAnalysis>
10+
<Copyright>Copyright © Medidata Solutions, Inc. $([System.DateTime]::Now.Year)</Copyright>
11+
<Authors>Medidata Solutions</Authors>
12+
<RepositoryType>git</RepositoryType>
13+
<RepositoryUrl>https://github.com/mdsol/mauth-client-dotnet</RepositoryUrl>
14+
<PublishRepositoryUrl>true</PublishRepositoryUrl>
15+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
16+
<Company>Medidata Solutions, Inc.</Company>
17+
<PackageProjectUrl>https://github.com/mdsol/mauth-client-dotnet</PackageProjectUrl>
18+
<PackageLicenseUrl>https://github.com/mdsol/mauth-client-dotnet/blob/master/LICENSE.md</PackageLicenseUrl>
19+
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
20+
<Product>Medidata Platform</Product>
21+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
22+
<EmbedUntrackedSources>true</EmbedUntrackedSources>
23+
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
24+
<IncludeSourceRevisionInInformationalVersion>true</IncludeSourceRevisionInInformationalVersion>
25+
</PropertyGroup>
26+
27+
<ItemGroup>
28+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
29+
</ItemGroup>
30+
</Project>

README.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,11 @@ public async Task<HttpResponseMessage> SignAndSendRequest(HttpRequestMessage req
124124
}
125125
}
126126
```
127-
The `SignVersions` parameter can be used to specify which protocol version to sign outgoing requests. Like as:
128-
`SignVersions = MAuthVersion.MWS`: signs with `MWS` protocol only.
129-
`SignVersions = MAuthVersion.MWS | MAuthVersion.MWSV2` : signs with both `MWS` and `MWSV2` protocol.
130-
If not supplied, it sign by `MWS` protocol by default.
127+
128+
The `SignVersions` parameter can be used to specify which protocol version to sign outgoing requests with:
129+
- `SignVersions = MAuthVersion.MWS`: signs with the `MWS` protocol only.
130+
- `SignVersions = MAuthVersion.MWS | MAuthVersion.MWSV2` : signs with both the `MWS` and the `MWSV2` protocol.
131+
If not supplied, it signs with the `MWS` protocol by default.
131132

132133
Signing with `MWSV2` protocol supports query string.
133134

@@ -323,30 +324,30 @@ for authenticating the incoming requests.
323324

324325
##### What Cryptographic provider is used for the encryption/decryption?
325326

326-
In the latest version of 4.0.0, we are using the available dotnet security [System.Security.Cryptography] which works
327-
for both **.NET Framework 4.6.1** and **.NET Standard 2.0** in case of V2 protocol. However, for the continue support
328-
of V1 protcol, we are still maintaining the BouncyCastle library as mentioned below.
327+
In the latest version of 4.0.0, we are using the available dotnet security [System.Security.Cryptography](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography?view=dotnet-plat-ext-3.1)
328+
which works for both **.NET Framework 4.6.1** and **.NET Standard 2.0** when using the V2 protocol.
329+
However, to also support the V1 protcol, we are still maintaining the BouncyCastle library as mentioned below.
329330

330331
On the .NET Framework side (WebAPI, Owin, Core) we are using the latest version (as of date 1.81) of the
331332
[BouncyCastle](https://github.com/bcgit/bc-csharp) library; on the .NET Standard side (Core, AspNetCore) we are using
332333
the portable fork of the [BouncyCastle](https://github.com/onovotny/BouncyCastle-PCL) library.
333334

334335
##### What are the major changes in the 5.0.0 version?
335-
In this version we have removed the property `DisableV1` from `MAuthSigningOptions`. Instead, we have added new option as
336-
`SignVersions` in `MAuthSigningOptions` which takes enumeration values of MAuth protcol versions `MWS` and/ or `MWSV2` protocol.
337-
If this option is not provided, then it will sign in by `MWS` protocol as default.
336+
In this version we have removed the property `DisableV1` from `MAuthSigningOptions`. Instead, we have added new option as
337+
`SignVersions` in `MAuthSigningOptions` which takes enumeration values of MAuth protcol versions `MWS` and/ or `MWSV2` protocol.
338+
If this option is not provided, then it will sign in by `MWS` protocol as default.
338339

339340
##### What are the major changes in the 4.0.0 version?
340341

341342
In this version we have added support for V2 protocol which uses `MCC-Authentication` as MAuthHeader and `MCC-Time` as
342343
MAuthTimeHeader. And, this V2 protocol supports for signing and authenticating url with query string parameters.
343344
For Signing, we added two new options in `MAuthSigningOptions`: `MAuthVersion` which is mandatory and takes enumeration
344345
value of `MAuthVersion.MWSV2` for V2 protocol or `MAuthVersion.MWS` for continue of using V1 protocol.
345-
Another option `DisableV1` is `false` by default if not provided. But, it is needed to provide as `true` when the client
346+
Another option `DisableV1` is `false` by default if not provided. But, it is needed to provide as `true` when the client
346347
need to sign on by no more supporting V1 protocol.
347348

348-
Also while authentication, the logic defaults to check for V2 protcol header `MWSV2` and if fails then only fallback to
349-
check for V1 protocol header for `MWS`. Also, `MAuthOptionsBase` includes new option as `DisableV1` which is `false` by
349+
Also while authentication, the logic defaults to check for V2 protcol header `MWSV2` and if fails then only fallback to
350+
check for V1 protocol header for `MWS`. Also, `MAuthOptionsBase` includes new option as `DisableV1` which is `false` by
350351
default and need to be passed as `true` if the authenticating client no longer wants to support V1 protocol.
351352

352353
##### What are the major changes in the 2.0.0 version?

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: '{build}'
22
pull_requests:
33
do_not_increment_build_number: true
4-
image: Visual Studio 2017
4+
image: Visual Studio 2019
55
init:
66
- git config --global core.autocrlf true
77
nuget:

build/common.props

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/Medidata.MAuth.AspNetCore/Medidata.MAuth.AspNetCore.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
2-
<Import Project="..\..\build\common.props" />
32

43
<PropertyGroup>
5-
<TargetFramework>netcoreapp2.1</TargetFramework>
4+
<TargetFramework>netstandard2.0</TargetFramework>
65
<Description>This package contains an ASP.NET Core middleware to validate signed http requests with the Medidata MAuth protocol. The middleware communicates with an MAuth server in order to confirm the validity of the request authentication header. Include this package in your ASP.NET Core web api if you want to authenticate the api requests signed with the MAuth protocol.</Description>
76
<AssemblyTitle>Medidata.MAuth.AspNetCore</AssemblyTitle>
87
<AssemblyName>Medidata.MAuth.AspNetCore</AssemblyName>

src/Medidata.MAuth.Core/AsyncLazy.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
using System.Threading.Tasks;
4+
5+
namespace Medidata.MAuth.Core
6+
{
7+
internal class AsyncLazy<T> : Lazy<Task<T>>
8+
{
9+
public AsyncLazy(Func<T> valueFactory)
10+
: base(() => Task.Factory.StartNew(valueFactory))
11+
{
12+
}
13+
14+
public AsyncLazy(Func<Task<T>> taskFactory)
15+
: base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap())
16+
{
17+
}
18+
19+
public TaskAwaiter<T> GetAwaiter() => Value.GetAwaiter();
20+
21+
public ConfiguredTaskAwaitable<T> ConfigureAwait(bool continueOnCapturedContext)
22+
=> Value.ConfigureAwait(continueOnCapturedContext);
23+
}
24+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using Microsoft.Extensions.Caching.Memory;
3+
4+
namespace Medidata.MAuth.Core
5+
{
6+
/// <summary>
7+
/// Caching-related extension methods.
8+
/// </summary>
9+
public static class CacheExtensions
10+
{
11+
/// <summary>
12+
/// Get or create an item in the cache. If the specified key does not exist, the factory method will be executed to
13+
/// create a new item, and that item will be inserted into the cache with that key. Locking is based on the cache
14+
/// key, to prevent multiple concurrent factory methods from executing for a single key, but allow multiple concurrent
15+
/// factory methods to execute for different keys.
16+
/// </summary>
17+
/// <param name="cache">The memory cache.</param>
18+
/// <param name="key">The cache key.</param>
19+
/// <param name="factory">The factory method to create a new item if the key does not exist in the cache.</param>
20+
/// <typeparam name="TItem">The cached item type.</typeparam>
21+
/// <returns>The item that was retrieved from the cache or created.</returns>
22+
public static TItem GetOrCreateWithLock<TItem>(
23+
this IMemoryCache cache,
24+
object key,
25+
Func<ICacheEntry, TItem> factory)
26+
{
27+
if (cache.TryGetValue(key, out TItem item))
28+
{
29+
return item;
30+
}
31+
32+
var lockStr = string.Intern("mutex_" + key.GetHashCode());
33+
34+
lock (lockStr)
35+
{
36+
if (cache.TryGetValue(key, out item))
37+
{
38+
return item;
39+
}
40+
41+
ICacheEntry entry = cache.CreateEntry(key);
42+
item = factory(entry);
43+
entry.SetValue(item);
44+
entry.Dispose();
45+
return item;
46+
}
47+
}
48+
}
49+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.IO;
3+
using System.Net.Http;
4+
using System.Threading.Tasks;
5+
6+
namespace Medidata.MAuth.Core
7+
{
8+
internal static class HttpRequestMessageExtensions
9+
{
10+
public async static Task<byte[]> GetRequestContentAsBytesAsync(this HttpRequestMessage request)
11+
{
12+
return request.Content is null
13+
? Array.Empty<byte>()
14+
: await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
15+
}
16+
17+
#if NET5_0
18+
public static byte[] GetRequestContentAsBytes(this HttpRequestMessage request)
19+
{
20+
using (var memoryStream = new MemoryStream())
21+
{
22+
if (request.Content != null)
23+
{
24+
request.Content.ReadAsStream().CopyTo(memoryStream);
25+
}
26+
return memoryStream.ToArray();
27+
}
28+
}
29+
#endif
30+
}
31+
}

0 commit comments

Comments
 (0)