5
5
6
6
namespace NServiceBus . Encryption
7
7
{
8
+ using System . Collections ;
8
9
using System . Collections . Concurrent ;
9
10
using System . Collections . Generic ;
10
11
using System . Reflection ;
@@ -19,45 +20,74 @@ public class EncryptionMessageMutator : IMessageMutator
19
20
20
21
public object MutateOutgoing ( object message )
21
22
{
22
- EncryptObject ( message ) ;
23
+ ForEachMember ( message , EncryptMember , IsEncryptedMember ) ;
24
+
23
25
return message ;
24
26
}
25
27
26
- void EncryptObject ( object target )
28
+
29
+ public object MutateIncoming ( object message )
27
30
{
28
- var properties = GetAllProperties ( target ) ;
31
+ ForEachMember ( message , DecryptMember , IsEncryptedMember ) ;
32
+ return message ;
33
+ }
34
+
35
+ bool IsEncryptedMember ( MemberInfo arg )
36
+ {
37
+ if ( arg is PropertyInfo )
38
+ return ( ( PropertyInfo ) arg ) . IsEncryptedProperty ( ) ;
39
+
40
+ if ( arg is FieldInfo )
41
+ return ( ( FieldInfo ) arg ) . FieldType == typeof ( WireEncryptedString ) ;
42
+
43
+ return false ;
29
44
30
- foreach ( var property in properties )
45
+ }
46
+ void ForEachMember ( object root , Action < object , MemberInfo > action , Func < MemberInfo , bool > appliesTo )
47
+ {
48
+ if ( root == null || visitedMembers . Contains ( root ) )
49
+ return ;
50
+
51
+ visitedMembers . Add ( root ) ;
52
+
53
+ var members = GetFieldsAndProperties ( root ) ;
54
+
55
+ foreach ( var member in members )
31
56
{
32
- if ( property . IsEncryptedProperty ( ) )
33
- {
34
- EncryptProperty ( target , property ) ;
35
- continue ;
36
- }
37
57
38
- if ( property . PropertyType . IsPrimitive || IsSystemType ( property . PropertyType ) )
58
+ if ( appliesTo ( member ) )
59
+ action ( root , member ) ;
60
+
61
+ //don't recurse over primitives and system types
62
+ if ( member . ReflectedType . IsPrimitive || member . ReflectedType . IsSystemType ( ) )
39
63
continue ;
40
64
41
- //recurse
42
- EncryptObject ( property . GetValue ( target , null ) ) ;
65
+ var child = member . GetValue ( root ) ;
66
+
67
+ if ( child is IEnumerable )
68
+ foreach ( var item in ( IEnumerable ) child )
69
+ ForEachMember ( item , action , appliesTo ) ;
70
+ else
71
+ ForEachMember ( child , action , appliesTo ) ;
43
72
}
44
73
}
45
74
46
- void EncryptProperty ( object target , PropertyInfo encryptedProperty )
75
+
76
+ void EncryptMember ( object target , MemberInfo member )
47
77
{
48
- var valueToEncrypt = encryptedProperty . GetValue ( target , null ) ;
78
+ var valueToEncrypt = member . GetValue ( target ) ;
49
79
50
80
if ( valueToEncrypt == null )
51
81
return ;
52
82
53
83
if ( EncryptionService == null )
54
84
throw new InvalidOperationException (
55
85
String . Format ( "Cannot encrypt field {0} because no encryption service was configured." ,
56
- encryptedProperty . Name ) ) ;
86
+ member . Name ) ) ;
57
87
58
88
if ( valueToEncrypt is WireEncryptedString )
59
89
{
60
- var encryptedString = ( WireEncryptedString ) valueToEncrypt ;
90
+ var encryptedString = ( WireEncryptedString ) valueToEncrypt ;
61
91
EncryptWireEncryptedString ( encryptedString ) ;
62
92
63
93
if ( ! ConfigureEncryption . EnsureCompatibilityWithNSB2 )
@@ -69,50 +99,17 @@ void EncryptProperty(object target, PropertyInfo encryptedProperty)
69
99
}
70
100
else
71
101
{
72
- encryptedProperty . SetValue ( target , EncryptUserSpecifiedProperty ( valueToEncrypt ) , null ) ;
102
+ member . SetValue ( target , EncryptUserSpecifiedProperty ( valueToEncrypt ) ) ;
73
103
}
74
104
75
- Log . Debug ( encryptedProperty . Name + " encrypted successfully" ) ;
76
- }
77
-
78
-
79
- public object MutateIncoming ( object message )
80
- {
81
- DecryptObject ( message ) ;
82
- return message ;
105
+ Log . Debug ( member . Name + " encrypted successfully" ) ;
83
106
}
84
107
85
- void DecryptObject ( object target )
86
- {
87
- var properties = GetAllProperties ( target ) ;
88
-
89
- foreach ( var property in properties )
90
- {
91
- if ( property . IsEncryptedProperty ( ) )
92
- {
93
- DecryptProperty ( target , property ) ;
94
- continue ;
95
- }
96
-
97
- if ( property . PropertyType . IsPrimitive || IsSystemType ( property . PropertyType ) )
98
- continue ;
99
-
100
- //recurse
101
- DecryptObject ( property . GetValue ( target , null ) ) ;
102
- }
103
- }
104
108
105
- bool IsSystemType ( Type propertyType )
109
+ void DecryptMember ( object target , MemberInfo property )
106
110
{
107
- var nameOfContainingAssembly = propertyType . Assembly . FullName . ToLower ( ) ;
108
111
109
- return nameOfContainingAssembly . StartsWith ( "mscorlib" ) || nameOfContainingAssembly . StartsWith ( "system.core" ) ;
110
- }
111
-
112
- void DecryptProperty ( object target , PropertyInfo property )
113
- {
114
-
115
- var encryptedValue = property . GetValue ( target , null ) ;
112
+ var encryptedValue = property . GetValue ( target ) ;
116
113
117
114
if ( encryptedValue == null )
118
115
return ;
@@ -122,10 +119,10 @@ void DecryptProperty(object target, PropertyInfo property)
122
119
String . Format ( "Cannot decrypt field {0} because no encryption service was configured." , property . Name ) ) ;
123
120
124
121
if ( encryptedValue is WireEncryptedString )
125
- Decrypt ( ( WireEncryptedString ) encryptedValue ) ;
122
+ Decrypt ( ( WireEncryptedString ) encryptedValue ) ;
126
123
else
127
124
{
128
- property . SetValue ( target , DecryptUserSpecifiedProperty ( encryptedValue ) , null ) ;
125
+ property . SetValue ( target , DecryptUserSpecifiedProperty ( encryptedValue ) ) ;
129
126
}
130
127
131
128
Log . Debug ( property . Name + " decrypted successfully" ) ;
@@ -149,6 +146,9 @@ string DecryptUserSpecifiedProperty(object encryptedValue)
149
146
150
147
void Decrypt ( WireEncryptedString encryptedValue )
151
148
{
149
+ if ( encryptedValue . EncryptedValue == null )
150
+ throw new InvalidOperationException ( "Encrypted property is missing encryption data" ) ;
151
+
152
152
encryptedValue . Value = EncryptionService . Decrypt ( encryptedValue . EncryptedValue ) ;
153
153
}
154
154
@@ -170,21 +170,56 @@ void EncryptWireEncryptedString(WireEncryptedString wireEncryptedString)
170
170
wireEncryptedString . Value = null ;
171
171
172
172
}
173
- static IEnumerable < PropertyInfo > GetAllProperties ( object target )
173
+ static IEnumerable < MemberInfo > GetFieldsAndProperties ( object target )
174
174
{
175
175
if ( target == null )
176
- return new List < PropertyInfo > ( ) ;
176
+ return new List < MemberInfo > ( ) ;
177
177
178
178
var messageType = target . GetType ( ) ;
179
179
180
180
if ( ! cache . ContainsKey ( messageType ) )
181
- cache [ messageType ] = messageType . GetProperties ( )
181
+ cache [ messageType ] = messageType . GetMembers ( BindingFlags . Public | BindingFlags . Instance )
182
+ . Where ( m => m is FieldInfo || m is PropertyInfo )
182
183
. ToList ( ) ;
183
184
184
185
return cache [ messageType ] ;
185
186
}
186
- readonly static IDictionary < Type , IEnumerable < PropertyInfo > > cache = new ConcurrentDictionary < Type , IEnumerable < PropertyInfo > > ( ) ;
187
+
188
+ readonly HashSet < object > visitedMembers = new HashSet < object > ( ) ;
189
+
190
+ readonly static IDictionary < Type , IEnumerable < MemberInfo > > cache = new ConcurrentDictionary < Type , IEnumerable < MemberInfo > > ( ) ;
187
191
188
192
readonly static ILog Log = LogManager . GetLogger ( typeof ( IEncryptionService ) ) ;
189
193
}
194
+
195
+
196
+ public static class TypeExtensions
197
+ {
198
+ public static bool IsSystemType ( this Type propertyType )
199
+ {
200
+ var nameOfContainingAssembly = propertyType . Assembly . FullName . ToLower ( ) ;
201
+
202
+ return nameOfContainingAssembly . StartsWith ( "mscorlib" ) || nameOfContainingAssembly . StartsWith ( "system.core" ) ;
203
+ }
204
+ }
205
+
206
+ public static class MemberInfoExtensions
207
+ {
208
+ public static object GetValue ( this MemberInfo member , object source )
209
+ {
210
+ if ( member is FieldInfo )
211
+ return ( ( FieldInfo ) member ) . GetValue ( source ) ;
212
+
213
+ return ( ( PropertyInfo ) member ) . GetValue ( source , null ) ;
214
+ }
215
+
216
+ public static void SetValue ( this MemberInfo member , object target , object value )
217
+ {
218
+ if ( member is FieldInfo )
219
+ ( ( FieldInfo ) member ) . SetValue ( target , value ) ;
220
+ else
221
+ ( ( PropertyInfo ) member ) . SetValue ( target , value , null ) ;
222
+ }
223
+
224
+ }
190
225
}
0 commit comments