Skip to content

Commit b5406bd

Browse files
author
claudiamurialdo
committed
Merge branch 'release-1.20' of https://github.com/genexuslabs/DotNetClasses into release-1.20
# Conflicts: # dotnet/test/Directory.Build.props
2 parents 4afbd53 + 4b82408 commit b5406bd

File tree

3 files changed

+133
-25
lines changed

3 files changed

+133
-25
lines changed

dotnet/src/dotnetframework/GxClasses/Domain/GxCollections.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -736,9 +736,9 @@ public void AddObjectProperty(object prop, bool includeState)
736736
if (bc != null)
737737
jarray.Add(bc.GetJSONObject(includeState));
738738
else
739-
jarray.Add(ijsonprop.GetJSONObject());
740-
}
741-
else if (prop is DateTime)
739+
jarray.Add(ijsonprop.GetJSONObject());
740+
}
741+
else if (prop is DateTime)
742742
{
743743
jarray.Add(DateTimeUtil.TToC2((DateTime)prop, false));
744744
}
@@ -1568,12 +1568,32 @@ public void AddObjectProperty(string name, object prop, bool includeState, bool
15681568
JsonObj.Put(name, prop);
15691569
}
15701570
}
1571+
else if (prop is decimal)
1572+
{
1573+
JsonObj.Put(name, RemoveInternalTrailingZeroes((decimal)prop));
1574+
}
15711575
else
15721576
{
15731577
JsonObj.Put(name, prop);
15741578
}
15751579
}
15761580
}
1581+
static decimal RemoveInternalTrailingZeroes(decimal dec)
1582+
{
1583+
if (GetDecimalScale(dec) > 0)
1584+
{
1585+
string strdec = dec.ToString(CultureInfo.InvariantCulture);
1586+
return decimal.Parse(strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec, CultureInfo.InvariantCulture);
1587+
}
1588+
else
1589+
return dec;
1590+
1591+
}
1592+
static int GetDecimalScale(decimal value)
1593+
{
1594+
int[] bits = decimal.GetBits(value);
1595+
return (bits[3] >> 16) & 0xFF;
1596+
}
15771597
public Object GetJSONObject(bool includeState, bool includeNoInitialized)
15781598
{
15791599
JsonObj.Clear();
@@ -2065,7 +2085,6 @@ public object Item(int index, int i)
20652085
return innerArray[index][i];
20662086
}
20672087
}
2068-
20692088
[CollectionDataContract(Name = "GxUnknownObjectCollection")]
20702089
[KnownType(typeof(GxSimpleCollection<object>))]
20712090
[KnownType(typeof(GxStringCollection))]
@@ -2420,13 +2439,14 @@ public interface IGxCollection<T> : IGxCollection
24202439
{
24212440
T GetNumeric(int idx);
24222441
}
2423-
24242442
public interface IGxExternalObject
24252443
{
24262444
object ExternalInstance { get; set; }
24272445
}
24282446
public class GXExternalCollection<T> : IGxCollection where T : IGxExternalObject
24292447
{
2448+
// T represents the type of the SDT wrapper for the external instance. E.g SdtWorkflowUser
2449+
// Instance is a list of ExternalType, whose concrete type is unknown. E.g. GXflow.API.User
24302450
IList instance;
24312451

24322452
public string _containedType;

dotnet/src/dotnetframework/GxClasses/Middleware/GXHttp.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,21 +1707,29 @@ protected string GetObjectAccessWebToken(String cmpCtx)
17071707
return GetSecureSignedToken(cmpCtx, string.Empty, this.context);
17081708
}
17091709

1710-
protected string GetSecureSignedToken(String cmpCtx, object Value, IGxContext context)
1710+
protected string GetSecureSignedToken(String cmpCtx, object value, IGxContext context)
17111711
{
1712-
return GetSecureSignedToken(cmpCtx, Serialize(Value), context);
1712+
if (value is IGxJSONSerializable)
1713+
return GetSecureSignedHashedToken(cmpCtx, SecureTokenHelper.GetTokenValue(value as IGxJSONSerializable), context);
1714+
else
1715+
return GetSecureSignedToken(cmpCtx, Serialize(value), context);
17131716
}
17141717

17151718
protected string GetSecureSignedToken(String cmpCtx, GxUserType Value, IGxContext context)
17161719
{
1717-
return GetSecureSignedToken(cmpCtx, Serialize(Value), context);
1720+
return GetSecureSignedHashedToken(cmpCtx, SecureTokenHelper.GetTokenValue(Value), context);
17181721
}
17191722

17201723

17211724
protected string GetSecureSignedToken(string cmpCtx, string value, IGxContext context)
17221725
{
17231726
return WebSecurityHelper.Sign(PgmInstanceId(cmpCtx), string.Empty, value, SecureTokenHelper.SecurityMode.Sign, context);
17241727
}
1728+
private string GetSecureSignedHashedToken(string cmpCtx, TokenValue tokenValue, IGxContext context)
1729+
{
1730+
return WebSecurityHelper.Sign(PgmInstanceId(cmpCtx), string.Empty, tokenValue, SecureTokenHelper.SecurityMode.Sign, context);
1731+
}
1732+
17251733
protected bool VerifySecureSignedToken(string cmpCtx, Object value, string pic, string signedToken, IGxContext context)
17261734
{
17271735
GxUserType SDT = value as GxUserType;

dotnet/src/dotnetframework/GxClasses/Security/WebSecurity.cs

Lines changed: 97 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ public static string Sign(string pgmName, string issuer, string value, SecurityM
3232
{
3333
return SecureTokenHelper.Sign(new WebSecureToken { ProgramName = pgmName, Issuer = issuer, Value = string.IsNullOrEmpty(value) ? string.Empty: StripInvalidChars(value) }, mode, GetSecretKey(context));
3434
}
35+
internal static string Sign(string pgmName, string issuer, TokenValue tokenValue, SecurityMode mode, IGxContext context)
36+
{
37+
return SecureTokenHelper.Sign(new WebSecureToken {
38+
ProgramName = pgmName,
39+
Issuer = issuer,
40+
ValueType = tokenValue.ValueType,
41+
Value = string.IsNullOrEmpty(tokenValue.Value) ? string.Empty : StripInvalidChars(tokenValue.Value) },
42+
mode, GetSecretKey(context));
43+
}
3544

3645
private static string GetSecretKey(IGxContext context)
3746
{
@@ -88,30 +97,63 @@ public static bool Verify(string pgmName, string issuer, string value, string jw
8897

8998
internal static bool VerifySecureSignedSDTToken(string cmpCtx, IGxCollection value, string signedToken, IGxContext context)
9099
{
91-
WebSecureToken Token = SecureTokenHelper.getWebSecureToken(signedToken, GetSecretKey(context));
92-
if (Token == null)
100+
WebSecureToken token = SecureTokenHelper.getWebSecureToken(signedToken, GetSecretKey(context));
101+
if (token == null)
93102
return false;
94-
IGxCollection PayloadObject = (IGxCollection)value.Clone();
95-
PayloadObject.FromJSonString(Token.Value);
96-
return GxUserType.IsEqual(value, PayloadObject);
103+
if (token.ValueType == SecureTokenHelper.ValueTypeHash)
104+
{
105+
return VerifyTokenHash(value.ToJSonString(), token);
106+
}
107+
else
108+
{
109+
IGxCollection PayloadObject = (IGxCollection)value.Clone();
110+
PayloadObject.FromJSonString(token.Value);
111+
return GxUserType.IsEqual(value, PayloadObject);
112+
}
97113
}
98114

99115
internal static bool VerifySecureSignedSDTToken(string cmpCtx, GxUserType value, string signedToken, IGxContext context)
100116
{
101-
WebSecureToken Token = SecureTokenHelper.getWebSecureToken(signedToken, GetSecretKey(context));
102-
if (Token == null)
117+
WebSecureToken token = SecureTokenHelper.getWebSecureToken(signedToken, GetSecretKey(context));
118+
if (token == null)
103119
return false;
104-
GxUserType PayloadObject = (GxUserType)value.Clone();
105-
PayloadObject.FromJSonString(Token.Value);
106-
return GxUserType.IsEqual(value, PayloadObject);
107-
}
120+
if (token.ValueType == ValueTypeHash)
121+
{
122+
return VerifyTokenHash(value.ToJSonString(), token);
123+
}
124+
else
125+
{
126+
GxUserType PayloadObject = (GxUserType)value.Clone();
127+
PayloadObject.FromJSonString(token.Value);
128+
return GxUserType.IsEqual(value, PayloadObject);
129+
}
108130

131+
}
109132

133+
private static bool VerifyTokenHash(string payloadJsonString, WebSecureToken token)
134+
{
135+
string hash = GetHash(payloadJsonString);
136+
if (hash != token.Value)
137+
{
138+
GXLogging.Error(_log, $"WebSecurity Token Verification error - Hash mismatch '{hash}' <> '{token.Value}'");
139+
GXLogging.Debug(_log, "Payload TokenOriginalValue: " + payloadJsonString);
140+
return false;
141+
}
142+
return true;
143+
}
144+
}
145+
internal class TokenValue
146+
{
147+
internal string Value { get; set; }
148+
internal string ValueType { get; set; }
110149
}
150+
111151
[SecuritySafeCritical]
112152
public static class SecureTokenHelper
113153
{
114154
private static readonly ILog _log = LogManager.GetLogger(typeof(GeneXus.Web.Security.SecureTokenHelper));
155+
internal const string ValueTypeHash = "hash";
156+
const int MaxTokenValueLength = 1024;
115157

116158
public enum SecurityMode
117159
{
@@ -128,6 +170,10 @@ internal static WebSecureToken getWebSecureToken(string signedToken, string secr
128170
using (var hmac = new System.Security.Cryptography.HMACSHA256(bSecretKey))
129171
{
130172
var handler = new JwtSecurityTokenHandler();
173+
if (signedToken.Length >= handler.MaximumTokenSizeInBytes)
174+
{
175+
handler.MaximumTokenSizeInBytes = signedToken.Length + 1;
176+
}
131177
var validationParameters = new TokenValidationParameters
132178
{
133179
ClockSkew = TimeSpan.FromMinutes(1),
@@ -139,6 +185,7 @@ internal static WebSecureToken getWebSecureToken(string signedToken, string secr
139185
WebSecureToken outToken = new WebSecureToken();
140186
var claims = handler.ValidateToken(signedToken, validationParameters, out securityToken);
141187
outToken.Value = claims.Identities.First().Claims.First(c => c.Type == WebSecureToken.GXVALUE).Value;
188+
outToken.ValueType = claims.Identities.First().Claims.First(c => c.Type == WebSecureToken.GXVALUE_TYPE)?.Value ?? string.Empty;
142189
return outToken;
143190
}
144191
}
@@ -156,7 +203,8 @@ public static string Sign(WebSecureToken token, SecurityMode mode, string secret
156203
new Claim(WebSecureToken.GXISSUER, token.Issuer),
157204
new Claim(WebSecureToken.GXPROGRAM, token.ProgramName),
158205
new Claim(WebSecureToken.GXVALUE, token.Value),
159-
new Claim(WebSecureToken.GXEXPIRATION, token.Expiration.Subtract(new DateTime(1970, 1, 1)).TotalSeconds.ToString())
206+
new Claim(WebSecureToken.GXEXPIRATION, token.Expiration.Subtract(new DateTime(1970, 1, 1)).TotalSeconds.ToString()),
207+
new Claim(WebSecureToken.GXVALUE_TYPE, token.ValueType ?? string.Empty)
160208
}),
161209
notBefore: DateTime.UtcNow,
162210
expires: token.Expiration,
@@ -204,10 +252,38 @@ internal static bool Verify(string jwtToken, WebSecureToken outToken, string sec
204252
}
205253
}
206254
return ok;
207-
}
208-
}
255+
}
256+
internal static TokenValue GetTokenValue(IGxJSONSerializable obj)
257+
{
258+
259+
string jsonString = obj.ToJSonString();
209260

210-
[DataContract]
261+
if (jsonString.Length > MaxTokenValueLength)
262+
{
263+
string hash = GetHash(jsonString);
264+
GXLogging.Debug(_log, $"GetTokenValue: TokenValue is too long, using hash: {hash} instead of original value.");
265+
GXLogging.Debug(_log, $"Server TokenOriginalValue:" + jsonString);
266+
return new TokenValue() { Value = hash, ValueType = ValueTypeHash };
267+
}
268+
else
269+
{
270+
GXLogging.Debug(_log, $"GetTokenValue:" + jsonString);
271+
return new TokenValue() { Value = jsonString };
272+
}
273+
}
274+
internal static string GetHash(string jsonString)
275+
{
276+
using (var sha256 = System.Security.Cryptography.SHA256.Create())
277+
{
278+
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(jsonString));
279+
jsonString = Convert.ToBase64String(hashBytes);
280+
return jsonString;
281+
}
282+
}
283+
284+
}
285+
286+
[DataContract]
211287
public abstract class SecureToken : IGxJSONSerializable
212288
{
213289
public abstract string ToJSonString();
@@ -237,8 +313,9 @@ public class WebSecureToken: SecureToken
237313
internal const string GXPROGRAM = "gx-pgm";
238314
internal const string GXVALUE = "gx-val";
239315
internal const string GXEXPIRATION = "gx-exp";
316+
internal const string GXVALUE_TYPE = "gx-val-type";
240317

241-
[DataMember(Name = GXISSUER, IsRequired = true, EmitDefaultValue = false)]
318+
[DataMember(Name = GXISSUER, IsRequired = true, EmitDefaultValue = false)]
242319
public string Issuer { get; set; }
243320

244321
[DataMember(Name = GXPROGRAM, IsRequired = true, EmitDefaultValue = false)]
@@ -250,7 +327,9 @@ public class WebSecureToken: SecureToken
250327
[DataMember(Name = GXEXPIRATION, EmitDefaultValue = false)]
251328
public DateTime Expiration { get; set; }
252329

253-
public WebSecureToken()
330+
[DataMember(Name = GXVALUE_TYPE, EmitDefaultValue = false)]
331+
public string ValueType { get; set; }
332+
public WebSecureToken()
254333
{
255334
Expiration = DateTime.Now.AddDays(15);
256335
}
@@ -263,6 +342,7 @@ public override bool FromJSonString(string s)
263342
this.Value = wt.Value;
264343
this.ProgramName = wt.ProgramName;
265344
this.Issuer = wt.Issuer;
345+
this.ValueType = wt.ValueType;
266346
return true;
267347
}
268348
catch (Exception)

0 commit comments

Comments
 (0)