Skip to content

Commit

Permalink
Merge pull request #120 from dvsekhvalnov/rfc_7797
Browse files Browse the repository at this point in the history
Rfc 7797: unencoded and detached content support
  • Loading branch information
dvsekhvalnov authored Nov 4, 2019
2 parents 1bcb166 + f3a361b commit 1f49ec3
Show file tree
Hide file tree
Showing 27 changed files with 1,523 additions and 65 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2014-2015 dvsekhvalnov
Copyright (c) 2014-2019 dvsekhvalnov

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,44 @@ string json = Jose.JWT.Decode(token, "top secret");

## Additional utilities

### Unencoded and detached content (aka [RFC 7797](https://tools.ietf.org/html/rfc7797))
As of v2.5.0 library support `b64` header to control payload decoding and encoding and optional content detaching.

Encoding can be controlled with optional `JwtOptions` parameter, that support:
* `DetachPayload` - whether we'd like to omit payload part in token produced (`false` by default)
* `EncodePayload` - whether to apply base64url encoding to payload part (`true` by default)

Options can be mixed in any combinations. To match RFC 7797:

```C#
string token = Jose.JWT.Encode(json, secretKey, JwsAlgorithm.HS256, options: new JwtOptions { DetachPayload = true, EncodePayload = false});
```

or just skip payload for instance:

```C#
string token = Jose.JWT.Encode(json, secretKey, JwsAlgorithm.HS256, options: new JwtOptions { DetachPayload = true });
```

Decoding automatically respect `b64` header if present. In case of detached payload one can provide optional `payload` param:

```C#
string token = "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJSUzI1NiJ9..iyormYw6b0zKjx4K-fpeZO8xrLghkeUFMb2l4alz03CRLVdlXkdeKVG7N5lBbS-kXB4-8hH1ELFA5fUJzN2QYR6ZZIWjDF77HYTw7lsyjTJDNABjBFn-BIXlWatjNdgtRi2BZg2q_Wos87ZQT6Sl-h5hvxsFEsR0kGPMQ4Fjp-sxOyfnls8jAlziqmkpN-K6I3tK2vCLCQgnaN9sYrsIcrzuEA30YeXsgUe3m44yxLCXczXWKE3kgGiZ0MRpVvKOZt4B2DZLcRmNArhxjhWWd1nKZvv8c7kN0TqOjcNEUGWzwDs4ikCSz1aYKaLPXgjzpKnzbajUM117F3aCAaWH9g";

// will echo provided payload back as return value, for consistency
string json = Jose.JWT.Decode(token, PubKey(), payload: @"{""hello"": ""world""}");
```

also works with binary payloads:

```C#
string token = "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJSUzI1NiJ9..ToCewDcERVLuqImwDkOd9iSxvTC8vzh-HrhuohOIjWMrGpTZi2FdzVN4Ll3fb2Iz3s_hj-Lno_c6m_7VcmOHfRLC9sPjSu2q9dbNkKo8Zc2FQmsCBdQi06XGAEJZW2M9380pxoYKiJ51a4EbGl4Ag7lX3hXeTPYRMVifacgdlpg2SYZzDPZQbWvibgtXFsBsIqPd-8i6ucE2eMdaNeWMLsHv-b5s7uWn8hN2nMKHj000Qce5rSbpK58l2LNeWw4IR6wNOqSZfbeerMxq1u0p-ZKIQxP24MltaPjZtqMdD4AzjrP4UCEf7VaLSkSuNVSf6ZmLmE_OYgQuQe7adFdoPg";

// will echo provided payload back as return value, for consistency
byte[] payload = Jose.JWT.DecodeBytes(token, PubKey(), payload: BinaryPayload);
```


### Adding extra headers
jose-jwt allows to pass extra headers when encoding token to overide deafault values<sup>\*</sup>. `extraHeaders:` named param can be used, it accepts `IDictionary<string, object>` type.
jose-jwt is NOT allow to override `alg` and `enc` headers .
Expand Down
73 changes: 73 additions & 0 deletions UnitTests/CollectionsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Collections.Generic;
using Jose;
using Xunit;

namespace UnitTests
{
public class CollectionsTest
{
[Fact]
public void UnionArrays()
{
var src = new[] {"one", "two"};
var other = new[] {"two", "three"};

Assert.Equal(Collections.Union(src, other), new [] {"one", "two", "three"});
}

[Fact]
public void UnionArrayList()
{
var src = new[] { "one", "two" };
var other = new List<string>(new [] { "two", "three" });

Assert.Equal(Collections.Union(src, other), new[] { "one", "two", "three" });

}

[Fact]
public void UnionArraySet()
{
var src = new[] { "one", "two" };
var other = new HashSet<string>(new [] { "two", "three" });

Assert.Equal(Collections.Union(src, other), new[] { "one", "two", "three" });

}

[Fact]
public void UnionNonStrings()
{
var src = new[] { "one", "two" };
var other = new[] { 2, 3 };

Assert.Equal(Collections.Union(src, other), new[] { "one", "two", "2", "3" });
}

[Fact]
public void UnionNull()
{
var other = new[] { "two", "three" };

Assert.Equal(Collections.Union(null, other), new[] { "two", "three" });
}

[Fact]
public void UnionWithNonEnumerable()
{
var src = new[] { "one", "two" };
var other = 3;

Assert.Equal(Collections.Union(src, other), new[] { "one", "two" });
}

[Fact]
public void UnionWithNull()
{
var src = new[] { "one", "two" };

Assert.Equal(Collections.Union(src, null), new[] { "one", "two" });
}

}
}
89 changes: 89 additions & 0 deletions UnitTests/CompactTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,82 @@ public void ParseNull()
var exception = Assert.Throws<ArgumentNullException>(() => Compact.Parse(token));
}


[Fact]
public void Iterate3Parts()
{
//when
var test = Compact.Iterate("eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0.eyJoZWxsbyI6ICJ3b3JsZCJ9.chIoYWrQMA8XL5nFz6oLDJyvgHk2KA4BrFGrKymjC8E");

//then
Assert.Equal(test.Count, 3);
Assert.Equal(test.Next(), new byte[] { 123, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 44, 34, 99, 116, 121, 34, 58, 34, 116, 101, 120, 116, 92, 47, 112, 108, 97, 105, 110, 34, 125 });
Assert.Equal(test.Next(), new byte[] { 123, 34, 104, 101, 108, 108, 111, 34, 58, 32, 34, 119, 111, 114, 108, 100, 34, 125 });
Assert.Equal(test.Next(), new byte[] { 114, 18, 40, 97, 106, 208, 48, 15, 23, 47, 153, 197, 207, 170, 11, 12, 156, 175, 128, 121, 54, 40, 14, 1, 172, 81, 171, 43, 41, 163, 11, 193 });
Assert.Null(test.Next());
}


[Fact]
public void Iterate5Parts()
{
var test = Compact.Iterate("eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4R0NNIn0.FojyyzygtFOyNBjzqTRfr9HVHPrvtqbVUt9sXSuU59ZhLlzk7FrirryFnFGtj8YC9lx-IX156Ro9rBaJTCU_dfERd05DhPMffT40rdcDiLxfCLOY0E2PfsMyGQPhI6YtNBtf_sQjXWEBC59zH_VoswFAUstkvXY9eVVecoM-W9HFlIxwUXMVpEPtS96xZX5LMksDgJ9sYDTNa6EQOA0hfzw07fD_FFJShcueqJuoJjILYbad-AHbpnLTV4oTbFTYjskRxpEYQr9plFZsT4_xKiCU89slT9EFhmuaiUI_-NGdX-kNDyQZj2Vtid4LSOVv5kGxyygThuQb6wjr1AGe1g.O92pf8iqwlBIQmXA.YdGjkN7lzeKYIv743XlPRYTd3x4VA0xwa5WVoGf1hiHlhQuXGEg4Jv3elk4JoFJzgVuMMQMex8fpFFL3t5I4H9bH18pbrEo7wLXvGOsP971cuOOaXPxhX6qClkwx5qkWhcTbO_2AuJxzIaU9qBwtwWaxJm9axofAPYgYbdaMZkU4F5sFdaFY8IOe94wUA1Ocn_gxC_DYp9IEAyZut0j5RImmthPgiRO_0pK9OvusE_Xg3iGfdxu70x0KpoItuNwlEf0LUA.uP5jOGMxtDUiT6E3ubucBw");

//then
Assert.Equal(test.Count, 5);
Assert.Equal(test.Next(), new byte[] { 123, 34, 97, 108, 103, 34, 58, 34, 82, 83, 65, 49, 95, 53, 34, 44, 34, 101, 110, 99, 34, 58, 34, 65, 49, 50, 56, 71, 67, 77, 34, 125 });
Assert.Equal(test.Next(), new byte[] { 22, 136, 242, 203, 60, 160, 180, 83, 178, 52, 24, 243, 169, 52, 95, 175, 209, 213, 28, 250, 239, 182, 166, 213, 82, 223, 108, 93, 43, 148, 231, 214, 97, 46, 92, 228, 236, 90, 226, 174, 188, 133, 156, 81, 173, 143, 198, 2, 246, 92, 126, 33, 125, 121, 233, 26, 61, 172, 22, 137, 76, 37, 63, 117, 241, 17, 119, 78, 67, 132, 243, 31, 125, 62, 52, 173, 215, 3, 136, 188, 95, 8, 179, 152, 208, 77, 143, 126, 195, 50, 25, 3, 225, 35, 166, 45, 52, 27, 95, 254, 196, 35, 93, 97, 1, 11, 159, 115, 31, 245, 104, 179, 1, 64, 82, 203, 100, 189, 118, 61, 121, 85, 94, 114, 131, 62, 91, 209, 197, 148, 140, 112, 81, 115, 21, 164, 67, 237, 75, 222, 177, 101, 126, 75, 50, 75, 3, 128, 159, 108, 96, 52, 205, 107, 161, 16, 56, 13, 33, 127, 60, 52, 237, 240, 255, 20, 82, 82, 133, 203, 158, 168, 155, 168, 38, 50, 11, 97, 182, 157, 248, 1, 219, 166, 114, 211, 87, 138, 19, 108, 84, 216, 142, 201, 17, 198, 145, 24, 66, 191, 105, 148, 86, 108, 79, 143, 241, 42, 32, 148, 243, 219, 37, 79, 209, 5, 134, 107, 154, 137, 66, 63, 248, 209, 157, 95, 233, 13, 15, 36, 25, 143, 101, 109, 137, 222, 11, 72, 229, 111, 230, 65, 177, 203, 40, 19, 134, 228, 27, 235, 8, 235, 212, 1, 158, 214 });
Assert.Equal(test.Next(), new byte[] { 59, 221, 169, 127, 200, 170, 194, 80, 72, 66, 101, 192 });
Assert.Equal(test.Next(), new byte[] { 97, 209, 163, 144, 222, 229, 205, 226, 152, 34, 254, 248, 221, 121, 79, 69, 132, 221, 223, 30, 21, 3, 76, 112, 107, 149, 149, 160, 103, 245, 134, 33, 229, 133, 11, 151, 24, 72, 56, 38, 253, 222, 150, 78, 9, 160, 82, 115, 129, 91, 140, 49, 3, 30, 199, 199, 233, 20, 82, 247, 183, 146, 56, 31, 214, 199, 215, 202, 91, 172, 74, 59, 192, 181, 239, 24, 235, 15, 247, 189, 92, 184, 227, 154, 92, 252, 97, 95, 170, 130, 150, 76, 49, 230, 169, 22, 133, 196, 219, 59, 253, 128, 184, 156, 115, 33, 165, 61, 168, 28, 45, 193, 102, 177, 38, 111, 90, 198, 135, 192, 61, 136, 24, 109, 214, 140, 102, 69, 56, 23, 155, 5, 117, 161, 88, 240, 131, 158, 247, 140, 20, 3, 83, 156, 159, 248, 49, 11, 240, 216, 167, 210, 4, 3, 38, 110, 183, 72, 249, 68, 137, 166, 182, 19, 224, 137, 19, 191, 210, 146, 189, 58, 251, 172, 19, 245, 224, 222, 33, 159, 119, 27, 187, 211, 29, 10, 166, 130, 45, 184, 220, 37, 17, 253, 11, 80 });
Assert.Equal(test.Next(), new byte[] { 184, 254, 99, 56, 99, 49, 180, 53, 34, 79, 161, 55, 185, 187, 156, 7 });
Assert.Null(test.Next());
}


[Fact]
public void IterateEmptyTrailingPart()
{
//when
var test = Compact.Iterate("eyJhbGciOiJub25lIn0.eyJoZWxsbyI6ICJ3b3JsZCJ9.");

//then
Assert.Equal(test.Count, 3);
Assert.Equal(test.Next(), new byte[] { 123, 34, 97, 108, 103, 34, 58, 34, 110, 111, 110, 101, 34, 125 });
Assert.Equal(test.Next(), new byte[] { 123, 34, 104, 101, 108, 108, 111, 34, 58, 32, 34, 119, 111, 114, 108, 100, 34, 125 });
Assert.Equal(test.Next(), new byte[] { });
Assert.Null(test.Next());
}

[Fact]
public void IterateEmptyMiddlePart()
{
//when
var test = Compact.Iterate("eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..yVi-LdQQngN0C5WS.1McwSmhZzAtmmLp9y-OdnJwaJFo1nj_4ashmzl2LhubGf0Jl1OTEVJzsHZb7bkup7cGTkuxh6Vfv10ljHsjWf_URXoxP3stQqQeViVcuPV0y2Q_WHYzTNGZpmHGe-hM6gjDhyZyvu3yeXGFSvfPQmp9pWVOgDjI4RC0MQ83rzzn-rRdnZkznWjbmOPxwPrR72Qng0BISsEwbkPn4oO8-vlHkVmPpuDTaYzCT2ZR5K9JnIU8d8QdxEAGb7-s8GEJ1yqtd_w._umbK59DAKA3O89h15VoKQ");

//then
Assert.Equal(test.Count, 5);
Assert.Equal(test.Next(), new byte[] { 123, 34, 97, 108, 103, 34, 58, 34, 100, 105, 114, 34, 44, 34, 101, 110, 99, 34, 58, 34, 65, 49, 50, 56, 71, 67, 77, 34, 125 });
Assert.Equal(test.Next(), new byte[] { });
Assert.Equal(test.Next(), new byte[] { 201, 88, 190, 45, 212, 16, 158, 3, 116, 11, 149, 146 });
Assert.Equal(test.Next(), new byte[] { 212, 199, 48, 74, 104, 89, 204, 11, 102, 152, 186, 125, 203, 227, 157, 156, 156, 26, 36, 90, 53, 158, 63, 248, 106, 200, 102, 206, 93, 139, 134, 230, 198, 127, 66, 101, 212, 228, 196, 84, 156, 236, 29, 150, 251, 110, 75, 169, 237, 193, 147, 146, 236, 97, 233, 87, 239, 215, 73, 99, 30, 200, 214, 127, 245, 17, 94, 140, 79, 222, 203, 80, 169, 7, 149, 137, 87, 46, 61, 93, 50, 217, 15, 214, 29, 140, 211, 52, 102, 105, 152, 113, 158, 250, 19, 58, 130, 48, 225, 201, 156, 175, 187, 124, 158, 92, 97, 82, 189, 243, 208, 154, 159, 105, 89, 83, 160, 14, 50, 56, 68, 45, 12, 67, 205, 235, 207, 57, 254, 173, 23, 103, 102, 76, 231, 90, 54, 230, 56, 252, 112, 62, 180, 123, 217, 9, 224, 208, 18, 18, 176, 76, 27, 144, 249, 248, 160, 239, 62, 190, 81, 228, 86, 99, 233, 184, 52, 218, 99, 48, 147, 217, 148, 121, 43, 210, 103, 33, 79, 29, 241, 7, 113, 16, 1, 155, 239, 235, 60, 24, 66, 117, 202, 171, 93, 255 });
Assert.Equal(test.Next(), new byte[] { 254, 233, 155, 43, 159, 67, 0, 160, 55, 59, 207, 97, 215, 149, 104, 41 });
Assert.Null(test.Next());
}

[Fact]
public void IterateWithoutDecodingParts()
{
//when
var test = Compact.Iterate("eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0.eyJoZWxsbyI6ICJ3b3JsZCJ9.chIoYWrQMA8XL5nFz6oLDJyvgHk2KA4BrFGrKymjC8E");

//then
Assert.Equal(test.Count, 3);
Assert.Equal(test.Next(), new byte[] { 123, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 44, 34, 99, 116, 121, 34, 58, 34, 116, 101, 120, 116, 92, 47, 112, 108, 97, 105, 110, 34, 125 });
Assert.Equal(test.Next(false), new byte[] { 101, 121, 74, 111, 90, 87, 120, 115, 98, 121, 73, 54, 73, 67, 74, 51, 98, 51, 74, 115, 90, 67, 74, 57 });
Assert.Equal(test.Next(), new byte[] { 114, 18, 40, 97, 106, 208, 48, 15, 23, 47, 153, 197, 207, 170, 11, 12, 156, 175, 128, 121, 54, 40, 14, 1, 172, 81, 171, 43, 41, 163, 11, 193 });
Assert.Null(test.Next());
}

[Fact]
public void Serialize()
{
Expand Down Expand Up @@ -109,5 +185,18 @@ public void SerializeEmptyMiddlePart()
//then
Assert.Equal(test, "eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0..chIoYWrQMA8XL5nFz6oLDJyvgHk2KA4BrFGrKymjC8E");
}

[Fact]
public void SerializeUnencodedMix()
{
//when
var test = Compact.Serialize(
new byte[] { 123, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 44, 34, 99, 116, 121, 34, 58, 34, 116, 101, 120, 116, 92, 47, 112, 108, 97, 105, 110, 34, 125 },
"not encoded middle part",
new byte[] { 114, 18, 40, 97, 106, 208, 48, 15, 23, 47, 153, 197, 207, 170, 11, 12, 156, 175, 128, 121, 54, 40, 14, 1, 172, 81, 171, 43, 41, 163, 11, 193 });

//then
Assert.Equal(test, "eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0.not encoded middle part.chIoYWrQMA8XL5nFz6oLDJyvgHk2KA4BrFGrKymjC8E");
}
}
}
Loading

0 comments on commit 1f49ec3

Please sign in to comment.