@@ -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