@@ -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,33 +97,65 @@ 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 {
114-
115154 static readonly IGXLogger _log = GXLoggerFactory . GetLogger ( typeof ( SecureTokenHelper ) . FullName ) ;
155+ internal const string ValueTypeHash = "hash" ;
156+ const int MaxTokenValueLength = 1024 ;
116157
117- public enum SecurityMode
158+ public enum SecurityMode
118159 {
119160 Sign ,
120161 SignEncrypt ,
@@ -144,6 +185,7 @@ internal static WebSecureToken getWebSecureToken(string signedToken, string secr
144185 WebSecureToken outToken = new WebSecureToken ( ) ;
145186 var claims = handler . ValidateToken ( signedToken , validationParameters , out securityToken ) ;
146187 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 ;
147189 return outToken ;
148190 }
149191 }
@@ -161,7 +203,8 @@ public static string Sign(WebSecureToken token, SecurityMode mode, string secret
161203 new Claim ( WebSecureToken . GXISSUER , token . Issuer ) ,
162204 new Claim ( WebSecureToken . GXPROGRAM , token . ProgramName ) ,
163205 new Claim ( WebSecureToken . GXVALUE , token . Value ) ,
164- 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 )
165208 } ) ,
166209 notBefore : DateTime . UtcNow ,
167210 expires : token . Expiration ,
@@ -195,6 +238,7 @@ internal static bool Verify(string jwtToken, WebSecureToken outToken, string sec
195238 System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance | System . Reflection . BindingFlags . InvokeMethod , null , handler ,
196239 new object [ ] { jwtToken , validationParameters } ) ;
197240 Validators . ValidateIssuerSecurityKey ( jwtSecurityToken . SigningKey , jwtSecurityToken , validationParameters ) ;
241+
198242 outToken . Expiration = new DateTime ( 1970 , 1 , 1 ) . AddSeconds ( Double . Parse ( jwtSecurityToken . Claims . First ( c => c . Type == WebSecureToken . GXEXPIRATION ) . Value ) ) ;
199243 outToken . ProgramName = jwtSecurityToken . Claims . First ( c => c . Type == WebSecureToken . GXPROGRAM ) . Value ;
200244 outToken . Issuer = jwtSecurityToken . Claims . First ( c => c . Type == WebSecureToken . GXISSUER ) . Value ;
@@ -204,14 +248,42 @@ internal static bool Verify(string jwtToken, WebSecureToken outToken, string sec
204248 }
205249 catch ( Exception e )
206250 {
207- GXLogging . ErrorSanitized ( _log , string . Format ( "Web Token verify failed for Token '{0}'" , jwtToken ) , e ) ;
251+ GXLogging . Error ( _log , string . Format ( "Web Token verify failed for Token '{0}'" , jwtToken ) , e ) ;
208252 }
209253 }
210254 return ok ;
211- }
212- }
255+ }
256+ internal static TokenValue GetTokenValue ( IGxJSONSerializable obj )
257+ {
258+
259+ string jsonString = obj . ToJSonString ( ) ;
213260
214- [ 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 ]
215287 public abstract class SecureToken : IGxJSONSerializable
216288 {
217289 public abstract string ToJSonString ( ) ;
@@ -241,8 +313,9 @@ public class WebSecureToken: SecureToken
241313 internal const string GXPROGRAM = "gx-pgm" ;
242314 internal const string GXVALUE = "gx-val" ;
243315 internal const string GXEXPIRATION = "gx-exp" ;
316+ internal const string GXVALUE_TYPE = "gx-val-type" ;
244317
245- [ DataMember ( Name = GXISSUER , IsRequired = true , EmitDefaultValue = false ) ]
318+ [ DataMember ( Name = GXISSUER , IsRequired = true , EmitDefaultValue = false ) ]
246319 public string Issuer { get ; set ; }
247320
248321 [ DataMember ( Name = GXPROGRAM , IsRequired = true , EmitDefaultValue = false ) ]
@@ -254,7 +327,9 @@ public class WebSecureToken: SecureToken
254327 [ DataMember ( Name = GXEXPIRATION , EmitDefaultValue = false ) ]
255328 public DateTime Expiration { get ; set ; }
256329
257- public WebSecureToken ( )
330+ [ DataMember ( Name = GXVALUE_TYPE , EmitDefaultValue = false ) ]
331+ public string ValueType { get ; set ; }
332+ public WebSecureToken ( )
258333 {
259334 Expiration = DateTime . Now . AddDays ( 15 ) ;
260335 }
@@ -267,6 +342,7 @@ public override bool FromJSonString(string s)
267342 this . Value = wt . Value ;
268343 this . ProgramName = wt . ProgramName ;
269344 this . Issuer = wt . Issuer ;
345+ this . ValueType = wt . ValueType ;
270346 return true ;
271347 }
272348 catch ( Exception )
0 commit comments