1 //
2 // ChannelProtectionRequirements.cs
3 //
4 // Author:
5 //	Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005-2006 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Net.Security;
30 using System.Collections.Generic;
31 using System.ServiceModel;
32 using System.ServiceModel.Description;
33 using System.Xml;
34 
35 namespace System.ServiceModel.Security
36 {
37 	// Represents sp:SignedParts and sp:EncryptedParts in
38 	// sp:SupportingTokens/ws:Policy/.
39 	public class ChannelProtectionRequirements
40 	{
41 		bool is_readonly;
42 		ScopedMessagePartSpecification in_enc, in_sign, out_enc, out_sign;
43 
ChannelProtectionRequirements()44 		public ChannelProtectionRequirements ()
45 		{
46 			in_enc = new ScopedMessagePartSpecification ();
47 			out_enc = new ScopedMessagePartSpecification ();
48 			in_sign = new ScopedMessagePartSpecification ();
49 			out_sign = new ScopedMessagePartSpecification ();
50 		}
51 
ChannelProtectionRequirements( ChannelProtectionRequirements other)52 		public ChannelProtectionRequirements (
53 			ChannelProtectionRequirements other)
54 		{
55 			if (other == null)
56 				throw new ArgumentNullException ("other");
57 			in_enc = new ScopedMessagePartSpecification (other.in_enc);
58 			out_enc = new ScopedMessagePartSpecification (other.out_enc);
59 			in_sign = new ScopedMessagePartSpecification (other.in_sign);
60 			out_sign = new ScopedMessagePartSpecification (other.out_sign);
61 		}
62 
63 		public bool IsReadOnly {
64 			get { return is_readonly; }
65 		}
66 
67 		public ScopedMessagePartSpecification IncomingEncryptionParts {
68 			get { return in_enc; }
69 		}
70 
71 		public ScopedMessagePartSpecification IncomingSignatureParts {
72 			get { return in_sign; }
73 		}
74 
75 		public ScopedMessagePartSpecification OutgoingEncryptionParts {
76 			get { return out_enc; }
77 		}
78 
79 		public ScopedMessagePartSpecification OutgoingSignatureParts {
80 			get { return out_sign; }
81 		}
82 
Add( ChannelProtectionRequirements protectionRequirements)83 		public void Add (
84 			ChannelProtectionRequirements protectionRequirements)
85 		{
86 			Add (protectionRequirements, false);
87 		}
88 
Add( ChannelProtectionRequirements protectionRequirements, bool channelScopeOnly)89 		public void Add (
90 			ChannelProtectionRequirements protectionRequirements,
91 			bool channelScopeOnly)
92 		{
93 			if (is_readonly)
94 				throw new InvalidOperationException ("This ChannelProtectionRequirements is read-only.");
95 
96 			AddScopedParts (
97 				protectionRequirements.IncomingEncryptionParts,
98 				IncomingEncryptionParts,
99 				channelScopeOnly);
100 			AddScopedParts (
101 				protectionRequirements.IncomingSignatureParts,
102 				IncomingSignatureParts,
103 				channelScopeOnly);
104 			AddScopedParts (
105 				protectionRequirements.OutgoingEncryptionParts,
106 				OutgoingEncryptionParts,
107 				channelScopeOnly);
108 			AddScopedParts (
109 				protectionRequirements.OutgoingSignatureParts,
110 				OutgoingSignatureParts,
111 				channelScopeOnly);
112 		}
113 
AddScopedParts(ScopedMessagePartSpecification src, ScopedMessagePartSpecification dst, bool channelOnly)114 		void AddScopedParts (ScopedMessagePartSpecification src, ScopedMessagePartSpecification dst, bool channelOnly)
115 		{
116 			dst.AddParts (src.ChannelParts);
117 			if (channelOnly)
118 				return;
119 
120 			foreach (string a in src.Actions) {
121 				MessagePartSpecification m;
122 				src.TryGetParts (a, out m);
123 				src.AddParts (m);
124 			}
125 		}
126 
CreateInverse()127 		public ChannelProtectionRequirements CreateInverse ()
128 		{
129 			ChannelProtectionRequirements r =
130 				new ChannelProtectionRequirements ();
131 			AddScopedParts (in_enc, r.out_enc, false);
132 			AddScopedParts (in_sign, r.out_sign, false);
133 			AddScopedParts (out_enc, r.in_enc, false);
134 			AddScopedParts (out_sign, r.in_sign, false);
135 			return r;
136 		}
137 
MakeReadOnly()138 		public void MakeReadOnly ()
139 		{
140 			is_readonly = true;
141 			in_enc.MakeReadOnly ();
142 			in_sign.MakeReadOnly ();
143 			out_enc.MakeReadOnly ();
144 			out_sign.MakeReadOnly ();
145 		}
146 
CreateFromContract(ContractDescription cd)147 		internal static ChannelProtectionRequirements CreateFromContract (ContractDescription cd)
148 		{
149 			ChannelProtectionRequirements cp =
150 				new ChannelProtectionRequirements ();
151 			List<XmlQualifiedName> enc = new List<XmlQualifiedName> ();
152 			List<XmlQualifiedName> sig = new List<XmlQualifiedName> ();
153 			if (cd.HasProtectionLevel) {
154 				switch (cd.ProtectionLevel) {
155 				case ProtectionLevel.EncryptAndSign:
156 					cp.IncomingEncryptionParts.ChannelParts.IsBodyIncluded = true;
157 					cp.OutgoingEncryptionParts.ChannelParts.IsBodyIncluded = true;
158 					goto case ProtectionLevel.Sign;
159 				case ProtectionLevel.Sign:
160 					cp.IncomingSignatureParts.ChannelParts.IsBodyIncluded = true;
161 					cp.OutgoingSignatureParts.ChannelParts.IsBodyIncluded = true;
162 					break;
163 				}
164 			}
165 			foreach (OperationDescription od in cd.Operations) {
166 				foreach (MessageDescription md in od.Messages) {
167 					enc.Clear ();
168 					sig.Clear ();
169 					ProtectionLevel mplv =
170 						md.HasProtectionLevel ? md.ProtectionLevel :
171 						od.HasProtectionLevel ? od.ProtectionLevel :
172 						ProtectionLevel.EncryptAndSign; // default
173 					foreach (MessageHeaderDescription hd in md.Headers)
174 						AddPartProtectionRequirements (enc, sig, hd, cp);
175 
176 					ScopedMessagePartSpecification spec;
177 					bool includeBodyEnc = mplv == ProtectionLevel.EncryptAndSign;
178 					bool includeBodySig = mplv != ProtectionLevel.None;
179 
180 					// enc
181 					spec = md.Direction == MessageDirection.Input ?
182 						cp.IncomingEncryptionParts :
183 						cp.OutgoingEncryptionParts;
184 					spec.AddParts (new MessagePartSpecification (includeBodyEnc, enc.ToArray ()), md.Action);
185 					// sig
186 					spec = md.Direction == MessageDirection.Input ?
187 						cp.IncomingSignatureParts :
188 						cp.OutgoingSignatureParts;
189 					spec.AddParts (new MessagePartSpecification (includeBodySig, sig.ToArray ()), md.Action);
190 				}
191 			}
192 			return cp;
193 		}
194 
AddPartProtectionRequirements(List<XmlQualifiedName> enc, List<XmlQualifiedName> sig, MessageHeaderDescription pd, ChannelProtectionRequirements cp)195 		static void AddPartProtectionRequirements (List<XmlQualifiedName> enc,
196 			List<XmlQualifiedName> sig,
197 			MessageHeaderDescription pd,
198 			ChannelProtectionRequirements cp)
199 		{
200 			if (!pd.HasProtectionLevel)
201 				return; // no specific part indication
202 			switch (pd.ProtectionLevel) {
203 			case ProtectionLevel.EncryptAndSign:
204 				enc.Add (new XmlQualifiedName (pd.Name, pd.Namespace));
205 				goto case ProtectionLevel.Sign;
206 			case ProtectionLevel.Sign:
207 				sig.Add (new XmlQualifiedName (pd.Name, pd.Namespace));
208 				break;
209 			}
210 		}
211 	}
212 }
213