Skip to content

Commit

Permalink
Port to .NET Standard (#72)
Browse files Browse the repository at this point in the history
* Convert JWT project to netstandard
* Migrate and split up test projects
* Target .NETFramework 3.5
* Only depend on Csp package in netstandard
* Remove extraneous attributes
  • Loading branch information
nbarbettini authored and abatishchev committed Apr 18, 2017
1 parent 872cbf4 commit a2f104d
Show file tree
Hide file tree
Showing 27 changed files with 469 additions and 529 deletions.
18 changes: 0 additions & 18 deletions JWT.nuspec

This file was deleted.

42 changes: 26 additions & 16 deletions JWT.sln
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio 15
VisualStudioVersion = 15.0.26228.9
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT", "src\JWT\JWT.csproj", "{A80B51B8-DDF6-4026-98A4-B59653E50B38}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT.Tests", "tests\JWT.Tests\JWT.Tests.csproj", "{BF568781-D576-4545-A552-4DC839B1AF14}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{513CE2B5-E0D6-43BC-998A-A02CB2875479}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
JWT.nuspec = JWT.nuspec
package.cmd = package.cmd
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT", "src\JWT\JWT.csproj", "{2F79EB8D-5B33-4EA6-AC1A-89B107F043D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWT.Tests.Core", "tests\JWT.Tests.Core\JWT.Tests.Core.csproj", "{79341F14-151C-4231-B2A7-56DAC44CB25E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT.Tests.NETFramework", "tests\JWT.Tests.NETFramework\JWT.Tests.NETFramework.csproj", "{88E1DB97-3507-4D8C-9B3D-715DE2F9E414}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT.Tests.Common", "tests\JWT.Tests.Common\JWT.Tests.Common.csproj", "{5D0282D5-9CC4-4D42-A3F0-E18270F92184}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Release|Any CPU.Build.0 = Release|Any CPU
{BF568781-D576-4545-A552-4DC839B1AF14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF568781-D576-4545-A552-4DC839B1AF14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF568781-D576-4545-A552-4DC839B1AF14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF568781-D576-4545-A552-4DC839B1AF14}.Release|Any CPU.Build.0 = Release|Any CPU
{2F79EB8D-5B33-4EA6-AC1A-89B107F043D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F79EB8D-5B33-4EA6-AC1A-89B107F043D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F79EB8D-5B33-4EA6-AC1A-89B107F043D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F79EB8D-5B33-4EA6-AC1A-89B107F043D2}.Release|Any CPU.Build.0 = Release|Any CPU
{79341F14-151C-4231-B2A7-56DAC44CB25E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79341F14-151C-4231-B2A7-56DAC44CB25E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79341F14-151C-4231-B2A7-56DAC44CB25E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79341F14-151C-4231-B2A7-56DAC44CB25E}.Release|Any CPU.Build.0 = Release|Any CPU
{88E1DB97-3507-4D8C-9B3D-715DE2F9E414}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88E1DB97-3507-4D8C-9B3D-715DE2F9E414}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88E1DB97-3507-4D8C-9B3D-715DE2F9E414}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88E1DB97-3507-4D8C-9B3D-715DE2F9E414}.Release|Any CPU.Build.0 = Release|Any CPU
{5D0282D5-9CC4-4D42-A3F0-E18270F92184}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D0282D5-9CC4-4D42-A3F0-E18270F92184}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D0282D5-9CC4-4D42-A3F0-E18270F92184}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D0282D5-9CC4-4D42-A3F0-E18270F92184}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
11 changes: 0 additions & 11 deletions package.cmd

This file was deleted.

4 changes: 4 additions & 0 deletions src/JWT/Algorithms/RS256Algorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ public RS256Algorithm(X509Certificate2 cert)

public byte[] Sign(byte[] key, byte[] bytesToSign)
{
#if NETSTANDARD1_3
var rsa = (RSACryptoServiceProvider)_cert.GetRSAPrivateKey();
#else
var rsa = (RSACryptoServiceProvider)_cert.PrivateKey;
#endif
var param = new CspParameters
{
KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName,
Expand Down
98 changes: 32 additions & 66 deletions src/JWT/JWT.csproj
Original file line number Diff line number Diff line change
@@ -1,74 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A80B51B8-DDF6-4026-98A4-B59653E50B38}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>JWT</RootNamespace>
<AssemblyName>JWT</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworks>net35;netstandard1.3</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<PropertyGroup Condition="'$(TargetFramework)' == 'net35'">
<TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
<DefineConstants>NET35</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
<TargetFrameworkIdentifier>.NETStandard</TargetFrameworkIdentifier>
<DefineConstants>NETSTANDARD1_3</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<Company>Public Domain</Company>
<Copyright>Public Domain</Copyright>
<Description>JWT.NET, a JWT (JSON Web Token) implementation for .NET</Description>
<RepositoryUrl>https://github.com/jwt-dotnet/jwt</RepositoryUrl>
<PackageProjectUrl>https://github.com/jwt-dotnet/jwt</PackageProjectUrl>
<Authors>John Sheehan, Michael Lehenbauer, Alexander Batishchev</Authors>
<PackageLicenseUrl>https://creativecommons.org/publicdomain/zero/1.0/</PackageLicenseUrl>
<Version>3.0.0-beta1</Version>
<PackageTags>jwt json</PackageTags>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DocumentationFile>bin\Debug\netstandard1.3\JWT.xml</DocumentationFile>
<OutputPath>bin\Debug\netstandard1.3\</OutputPath>
</PropertyGroup>

<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.10.0.2\lib\net35\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="AlgorithmFactory.cs" />
<Compile Include="Algorithms\HMACSHA256Algorithm.cs" />
<Compile Include="Algorithms\HMACSHA384Algorithm.cs" />
<Compile Include="Algorithms\HMACSHA512Algorithm.cs" />
<Compile Include="Algorithms\RS256Algorithm.cs" />
<Compile Include="IBase64UrlEncoder.cs" />
<Compile Include="IDateTimeProvider.cs" />
<Compile Include="IJsonSerializer.cs" />
<Compile Include="IJwtAlgorithm.cs" />
<Compile Include="IJwtDecoder.cs" />
<Compile Include="IJwtEncoder.cs" />
<Compile Include="IJwtValidator.cs" />
<Compile Include="JsonWebToken.cs" />
<Compile Include="JwtBase64UrlEncoder.cs" />
<Compile Include="JwtDecoder.cs" />
<Compile Include="JwtEncoder.cs" />
<Compile Include="JwtHashAlgorithm.cs" />
<Compile Include="JwtValidator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Serializers\JsonNetSerializer.cs" />
<Compile Include="SignatureVerificationException.cs" />
<Compile Include="TokenExpiredException.cs" />
<Compile Include="UtcDateTimeProvider.cs" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="System.Security.Cryptography.Csp" Version="4.3.0" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
18 changes: 0 additions & 18 deletions src/JWT/Properties/AssemblyInfo.cs

This file was deleted.

4 changes: 0 additions & 4 deletions src/JWT/packages.config

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace JWT.Tests
{
internal class Customer
{
public string FirstName { get; set; }

public int Age { get; set; }
}
namespace JWT.Tests.Common
{
public class Customer
{
public string FirstName { get; set; }

public int Age { get; set; }
}
}
7 changes: 7 additions & 0 deletions tests/JWT.Tests.Common/JWT.Tests.Common.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard1.0</TargetFramework>
</PropertyGroup>

</Project>
19 changes: 19 additions & 0 deletions tests/JWT.Tests.Common/TestData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;

namespace JWT.Tests.Common
{
public static class TestData
{
public static readonly Customer Customer = new Customer { FirstName = "Bob", Age = 37 };

public const string Token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJGaXJzdE5hbWUiOiJCb2IiLCJBZ2UiOjM3fQ.cr0xw8c_HKzhFBMQrseSPGoJ0NPlRp_3BKzP96jwBdY";
public const string MalformedToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9eyJGaXJzdE5hbWUiOiJCb2IiLCJBZ2UiOjM3fQ.cr0xw8c_HKzhFBMQrseSPGoJ0NPlRp_3BKzP96jwBdY";
public const string ExtraHeadersToken = "eyJmb28iOiJiYXIiLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJGaXJzdE5hbWUiOiJCb2IiLCJBZ2UiOjM3fQ.slrbXF9VSrlX7LKsV-Umb_zEzWLxQjCfUOjNTbvyr1g";

public static readonly IDictionary<string, object> DictionaryPayload = new Dictionary<string, object>
{
{ "FirstName", "Bob" },
{ "Age", 37 }
};
}
}
101 changes: 101 additions & 0 deletions tests/JWT.Tests.Core/DecodeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System;
using FluentAssertions;
using JWT.Serializers;
using Xunit;
using JWT.Tests.Common;

namespace JWT.Tests
{
public class DecodeTests
{
[Fact]
public void Decode_Should_DecodeToken_To_Json_Encoded_String_With_JsonNet_Serializer()
{
var serializer = new JsonNetSerializer();
JsonWebToken.JsonSerializer = serializer;

var expectedPayload = serializer.Serialize(TestData.Customer);
var actualPayload = JsonWebToken.Decode(TestData.Token, "ABC", verify: false);

actualPayload.Should().Be(expectedPayload);
}

[Fact]
public void DecodeToObject_Should_DecodeToken_To_Dictionary_With_JsonNet_Serializer()
{
JsonWebToken.JsonSerializer = new JsonNetSerializer();

var actualPayload = JsonWebToken.DecodeToObject(TestData.Token, "ABC", verify: false);

actualPayload.ShouldBeEquivalentTo(TestData.DictionaryPayload, options => options.IncludingAllRuntimeProperties());
}

[Fact]
public void DecodeToObject_Should_DecodeToken_To_Generic_Type_With_JsonNet_Serializer()
{
JsonWebToken.JsonSerializer = new JsonNetSerializer();

var actualPayload = JsonWebToken.DecodeToObject<Customer>(TestData.Token, "ABC", verify: false);

actualPayload.ShouldBeEquivalentTo(TestData.Customer);
}

[Fact]
public void DecodeToObject_Should_Throw_Exception_On_MalformedToken()
{
Action action = () => JsonWebToken.DecodeToObject<Customer>(TestData.MalformedToken, "ABC", verify: false);

action.ShouldThrow<ArgumentException>();
}

[Fact]
public void DecodeToObject_Should_Throw_Exception_On_Invalid_Key()
{
Action action = () => JsonWebToken.DecodeToObject<Customer>(TestData.Token, "XYZ", verify: true);

action.ShouldThrow<SignatureVerificationException>();
}

[Fact]
public void DecodeToObject_Should_Throw_Exception_On_Invalid_Expiration_Claim()
{
var invalidexptoken = JsonWebToken.Encode(new { exp = "asdsad" }, "ABC", JwtHashAlgorithm.HS256);

Action action = () => JsonWebToken.DecodeToObject<Customer>(invalidexptoken, "ABC", verify: true);

action.ShouldThrow<SignatureVerificationException>();
}

[Fact]
public void DecodeToObject_Should_Throw_Exception_On_Expired_Claim()
{
var hourAgo = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0));
var unixTimestamp = (int)(hourAgo - new DateTime(1970, 1, 1)).TotalSeconds;
var expiredtoken = JsonWebToken.Encode(new { exp = unixTimestamp }, "ABC", JwtHashAlgorithm.HS256);

Action action = () => JsonWebToken.DecodeToObject<Customer>(expiredtoken, "ABC", verify: true);

action.ShouldThrow<TokenExpiredException>();
}

[Fact]
public void DecodeToObject_Should_Throw_Exception_Before_NotBefore_Becomes_Valid()
{
var nbf = (int)(DateTime.UtcNow.AddHours(1) - JwtValidator.UnixEpoch).TotalSeconds;
var invalidnbftoken = JsonWebToken.Encode(new { nbf = nbf }, "ABC", JwtHashAlgorithm.HS256);

Action action = () => JsonWebToken.DecodeToObject<Customer>(invalidnbftoken, "ABC", verify: true);

action.ShouldThrow<SignatureVerificationException>();
}

[Fact]
public void DecodeToObject_Should_Decode_Token_After_NotBefore_Becomes_Valid()
{
var nbf = (int)(DateTime.UtcNow - JwtValidator.UnixEpoch).TotalSeconds;
var validnbftoken = JsonWebToken.Encode(new { nbf = nbf }, "ABC", JwtHashAlgorithm.HS256);

JsonWebToken.DecodeToObject<Customer>(validnbftoken, "ABC", verify: true);
}
}
}
Loading

0 comments on commit a2f104d

Please sign in to comment.