1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.IdentityModel.Policy
6 {
7     using System.Collections.Generic;
8     using System.Collections.ObjectModel;
9     using System.IdentityModel.Claims;
10     using System.Security.Principal;
11 
12     interface IIdentityInfo
13     {
14         IIdentity Identity { get; }
15     }
16 
17     class UnconditionalPolicy : IAuthorizationPolicy, IDisposable
18     {
19         SecurityUniqueId id;
20         ClaimSet issuer;
21         ClaimSet issuance;
22         ReadOnlyCollection<ClaimSet> issuances;
23         DateTime expirationTime;
24         IIdentity primaryIdentity;
25         bool disposable = false;
26         bool disposed = false;
27 
UnconditionalPolicy(ClaimSet issuance)28         public UnconditionalPolicy(ClaimSet issuance)
29             : this(issuance, SecurityUtils.MaxUtcDateTime)
30         {
31         }
32 
UnconditionalPolicy(ClaimSet issuance, DateTime expirationTime)33         public UnconditionalPolicy(ClaimSet issuance, DateTime expirationTime)
34         {
35             if (issuance == null)
36                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("issuance");
37 
38             Initialize(ClaimSet.System, issuance, null, expirationTime);
39         }
40 
UnconditionalPolicy(ReadOnlyCollection<ClaimSet> issuances, DateTime expirationTime)41         public UnconditionalPolicy(ReadOnlyCollection<ClaimSet> issuances, DateTime expirationTime)
42         {
43             if (issuances == null)
44                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("issuances");
45 
46             Initialize(ClaimSet.System, null, issuances, expirationTime);
47         }
48 
UnconditionalPolicy(IIdentity primaryIdentity, ClaimSet issuance)49         internal UnconditionalPolicy(IIdentity primaryIdentity, ClaimSet issuance)
50             : this(issuance)
51         {
52             this.primaryIdentity = primaryIdentity;
53         }
54 
UnconditionalPolicy(IIdentity primaryIdentity, ClaimSet issuance, DateTime expirationTime)55         internal UnconditionalPolicy(IIdentity primaryIdentity, ClaimSet issuance, DateTime expirationTime)
56             : this(issuance, expirationTime)
57         {
58             this.primaryIdentity = primaryIdentity;
59         }
60 
UnconditionalPolicy(IIdentity primaryIdentity, ReadOnlyCollection<ClaimSet> issuances, DateTime expirationTime)61         internal UnconditionalPolicy(IIdentity primaryIdentity, ReadOnlyCollection<ClaimSet> issuances, DateTime expirationTime)
62             : this(issuances, expirationTime)
63         {
64             this.primaryIdentity = primaryIdentity;
65         }
66 
UnconditionalPolicy(UnconditionalPolicy from)67         UnconditionalPolicy(UnconditionalPolicy from)
68         {
69             this.disposable = from.disposable;
70             this.primaryIdentity = from.disposable ? SecurityUtils.CloneIdentityIfNecessary(from.primaryIdentity) : from.primaryIdentity;
71             if (from.issuance != null)
72             {
73                 this.issuance = from.disposable ? SecurityUtils.CloneClaimSetIfNecessary(from.issuance) : from.issuance;
74             }
75             else
76             {
77                 this.issuances = from.disposable ? SecurityUtils.CloneClaimSetsIfNecessary(from.issuances) : from.issuances;
78             }
79             this.issuer = from.issuer;
80             this.expirationTime = from.expirationTime;
81         }
82 
Initialize(ClaimSet issuer, ClaimSet issuance, ReadOnlyCollection<ClaimSet> issuances, DateTime expirationTime)83         void Initialize(ClaimSet issuer, ClaimSet issuance, ReadOnlyCollection<ClaimSet> issuances, DateTime expirationTime)
84         {
85             this.issuer = issuer;
86             this.issuance = issuance;
87             this.issuances = issuances;
88             this.expirationTime = expirationTime;
89             if (issuance != null)
90             {
91                 this.disposable = issuance is WindowsClaimSet;
92             }
93             else
94             {
95                 for (int i = 0; i < issuances.Count; ++i)
96                 {
97                     if (issuances[i] is WindowsClaimSet)
98                     {
99                         this.disposable = true;
100                         break;
101                     }
102                 }
103             }
104         }
105 
106         public string Id
107         {
108             get
109             {
110                 if (this.id == null)
111                     this.id = SecurityUniqueId.Create();
112                 return this.id.Value;
113             }
114         }
115 
116         public ClaimSet Issuer
117         {
118             get { return this.issuer; }
119         }
120 
121         internal IIdentity PrimaryIdentity
122         {
123             get
124             {
125                 ThrowIfDisposed();
126                 if (this.primaryIdentity == null)
127                 {
128                     IIdentity identity = null;
129                     if (this.issuance != null)
130                     {
131                         if (this.issuance is IIdentityInfo)
132                         {
133                             identity = ((IIdentityInfo)this.issuance).Identity;
134                         }
135                     }
136                     else
137                     {
138                         for (int i = 0; i < this.issuances.Count; ++i)
139                         {
140                             ClaimSet issuance = this.issuances[i];
141                             if (issuance is IIdentityInfo)
142                             {
143                                 identity = ((IIdentityInfo)issuance).Identity;
144                                 // Preferably Non-Anonymous
145                                 if (identity != null && identity != SecurityUtils.AnonymousIdentity)
146                                 {
147                                     break;
148                                 }
149                             }
150                         }
151                     }
152                     this.primaryIdentity = identity ?? SecurityUtils.AnonymousIdentity;
153                 }
154                 return this.primaryIdentity;
155             }
156         }
157 
158         internal ReadOnlyCollection<ClaimSet> Issuances
159         {
160             get
161             {
162                 ThrowIfDisposed();
163                 if (this.issuances == null)
164                 {
165                     List<ClaimSet> issuances = new List<ClaimSet>(1);
166                     issuances.Add(issuance);
167                     this.issuances = issuances.AsReadOnly();
168                 }
169                 return this.issuances;
170             }
171         }
172 
173         public DateTime ExpirationTime
174         {
175             get { return this.expirationTime; }
176         }
177 
178         internal bool IsDisposable
179         {
180             get { return this.disposable; }
181         }
182 
Clone()183         internal UnconditionalPolicy Clone()
184         {
185             ThrowIfDisposed();
186             return (this.disposable) ? new UnconditionalPolicy(this) : this;
187         }
188 
Dispose()189         public virtual void Dispose()
190         {
191             if (this.disposable && !this.disposed)
192             {
193                 this.disposed = true;
194                 SecurityUtils.DisposeIfNecessary(this.primaryIdentity as WindowsIdentity);
195                 SecurityUtils.DisposeClaimSetIfNecessary(this.issuance);
196                 SecurityUtils.DisposeClaimSetsIfNecessary(this.issuances);
197             }
198         }
199 
ThrowIfDisposed()200         void ThrowIfDisposed()
201         {
202             if (this.disposed)
203             {
204                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(this.GetType().FullName));
205             }
206         }
207 
Evaluate(EvaluationContext evaluationContext, ref object state)208         public virtual bool Evaluate(EvaluationContext evaluationContext, ref object state)
209         {
210             ThrowIfDisposed();
211             if (this.issuance != null)
212             {
213                 evaluationContext.AddClaimSet(this, this.issuance);
214             }
215             else
216             {
217                 for (int i = 0; i < this.issuances.Count; ++i)
218                 {
219                     if (this.issuances[i] != null)
220                     {
221                         evaluationContext.AddClaimSet(this, this.issuances[i]);
222                     }
223                 }
224             }
225 
226             // Preferably Non-Anonymous
227             if (this.PrimaryIdentity != null && this.PrimaryIdentity != SecurityUtils.AnonymousIdentity)
228             {
229                 IList<IIdentity> identities;
230                 object obj;
231                 if (!evaluationContext.Properties.TryGetValue(SecurityUtils.Identities, out obj))
232                 {
233                     identities = new List<IIdentity>(1);
234                     evaluationContext.Properties.Add(SecurityUtils.Identities, identities);
235                 }
236                 else
237                 {
238                     // null if other overrides the property with something else
239                     identities = obj as IList<IIdentity>;
240                 }
241 
242                 if (identities != null)
243                 {
244                     identities.Add(this.PrimaryIdentity);
245                 }
246             }
247 
248             evaluationContext.RecordExpirationTime(this.expirationTime);
249             return true;
250         }
251     }
252 }
253