Merge pull request #2394 from Mailaender/patch-1
[mono.git] / mcs / class / corlib / System.Security.Principal / WindowsIdentity.cs
1 //
2 // System.Security.Principal.WindowsIdentity
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //      Sebastien Pouliot (sebastien@ximian.com)
7 //
8 // (C) 2002 Ximian, Inc (http://www.ximian.com)
9 // Portions (C) 2003 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Runtime.CompilerServices;
33 using System.Runtime.InteropServices;
34 using System.Runtime.Serialization;
35 using System.Security.Permissions;
36 using System.Security.Claims;
37 using Microsoft.Win32.SafeHandles;
38
39 namespace System.Security.Principal {
40
41         [Serializable]
42         [ComVisible (true)]
43         public class WindowsIdentity :
44         System.Security.Claims.ClaimsIdentity,
45         IIdentity, IDeserializationCallback, ISerializable, IDisposable {
46                 private IntPtr _token;
47                 private string _type;
48                 private WindowsAccountType _account;
49                 private bool _authenticated;
50                 private string _name;
51                 private SerializationInfo _info;
52
53                 static private IntPtr invalidWindows = IntPtr.Zero;
54
55                 [NonSerialized]
56                 public new const string DefaultIssuer = "AD AUTHORITY";
57
58                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
59                 public WindowsIdentity (IntPtr userToken) 
60                         : this (userToken, null, WindowsAccountType.Normal, false)
61                 {
62                 }
63
64                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
65                 public WindowsIdentity (IntPtr userToken, string type) 
66                         : this (userToken, type, WindowsAccountType.Normal, false)
67                 {
68                 }
69
70                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
71                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType)
72                         : this (userToken, type, acctType, false)
73                 {
74                 }
75
76                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
77                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
78                 {
79                         _type = type;
80                         _account = acctType;
81                         _authenticated = isAuthenticated;
82                         _name = null;
83                         // last - as it can override some fields
84                         SetToken (userToken);
85                 }
86
87                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
88                 public WindowsIdentity (string sUserPrincipalName) 
89                         : this (sUserPrincipalName, null)
90                 {
91                 }
92
93                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
94                 public WindowsIdentity (string sUserPrincipalName, string type)
95                 {
96                         if (sUserPrincipalName == null)
97                                 throw new NullReferenceException ("sUserPrincipalName");
98
99                         // TODO: Windows 2003 compatibility should be done in runtime
100                         IntPtr token = GetUserToken (sUserPrincipalName);
101                         if ((!Environment.IsUnix) && (token == IntPtr.Zero)) {
102                                 throw new ArgumentException ("only for Windows Server 2003 +");
103                         }
104
105                         _authenticated = true;
106                         _account = WindowsAccountType.Normal;
107                         _type = type;
108                         // last - as it can override some fields
109                         SetToken (token);
110                 }
111
112                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
113                 public WindowsIdentity (SerializationInfo info, StreamingContext context)
114                 {
115                         _info = info;
116                 }
117
118                 internal WindowsIdentity (ClaimsIdentity claimsIdentity, IntPtr userToken)
119                         : base (claimsIdentity)
120                 {
121                         if (userToken != IntPtr.Zero && userToken.ToInt64() > 0)
122                         {
123                                 SetToken (userToken);
124                         }
125                 }
126
127                 [ComVisible (false)]
128                 public void Dispose ()
129                 {
130                         _token = IntPtr.Zero;
131                 }
132                 
133                 [ComVisible (false)]
134                 protected virtual void Dispose (bool disposing)
135                 {
136                         _token = IntPtr.Zero;
137                 }
138                 // static methods
139
140                 public static WindowsIdentity GetAnonymous ()
141                 {
142                         WindowsIdentity id = null;
143                         if (Environment.IsUnix) {
144                                 id = new WindowsIdentity ("nobody");
145                                 // special case
146                                 id._account = WindowsAccountType.Anonymous;
147                                 id._authenticated = false;
148                                 id._type = String.Empty;
149                         }
150                         else {
151                                 id = new WindowsIdentity (IntPtr.Zero, String.Empty, WindowsAccountType.Anonymous, false);
152                                 // special case (don't try to resolve the name)
153                                 id._name = String.Empty;
154                         }
155                         return id;
156                 }
157
158                 public static WindowsIdentity GetCurrent ()
159                 {
160                         return new WindowsIdentity (GetCurrentToken (), null, WindowsAccountType.Normal, true);
161                 }
162                 [MonoTODO ("need icall changes")]
163                 public static WindowsIdentity GetCurrent (bool ifImpersonating)
164                 {
165                         throw new NotImplementedException ();
166                 }
167
168                 [MonoTODO ("need icall changes")]
169                 public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess)
170                 {
171                         throw new NotImplementedException ();
172                 }
173                 // methods
174
175                 public virtual WindowsImpersonationContext Impersonate ()
176                 {
177                         return new WindowsImpersonationContext (_token);
178                 }
179
180                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
181                 public static WindowsImpersonationContext Impersonate (IntPtr userToken)
182                 {
183                         return new WindowsImpersonationContext (userToken);
184                 }
185
186                 // properties
187                 sealed override
188                 public string AuthenticationType {
189                         get { return _type; }
190                 }
191
192                 public virtual bool IsAnonymous
193                 {
194                         get { return (_account == WindowsAccountType.Anonymous); }
195                 }
196
197                 override
198                 public bool IsAuthenticated
199                 {
200                         get { return _authenticated; }
201                 }
202
203                 public virtual bool IsGuest
204                 {
205                         get { return (_account == WindowsAccountType.Guest); }
206                 }
207
208                 public virtual bool IsSystem
209                 {
210                         get { return (_account == WindowsAccountType.System); }
211                 }
212
213                 override
214                 public string Name
215                 {
216                         get {
217                                 if (_name == null) {
218                                         // revolve name (runtime)
219                                         _name = GetTokenName (_token);
220                                 }
221                                 return _name; 
222                         }
223                 }
224
225                 public virtual IntPtr Token
226                 {
227                         get { return _token; }
228                 }
229                 [MonoTODO ("not implemented")]
230                 public IdentityReferenceCollection Groups {
231                         get { throw new NotImplementedException (); }
232                 }
233
234                 [MonoTODO ("not implemented")]
235                 [ComVisible (false)]
236                 public TokenImpersonationLevel ImpersonationLevel {
237                         get { throw new NotImplementedException (); }
238                 }
239
240                 [MonoTODO ("not implemented")]
241                 [ComVisible (false)]
242                 public SecurityIdentifier Owner {
243                         get { throw new NotImplementedException (); }
244                 }
245
246                 [MonoTODO ("not implemented")]
247                 [ComVisible (false)]
248                 public SecurityIdentifier User {
249                         get { throw new NotImplementedException (); }
250                 }
251                 void IDeserializationCallback.OnDeserialization (object sender)
252                 {
253                         _token = (IntPtr) _info.GetValue ("m_userToken", typeof (IntPtr));
254                         // can't trust this alone - we must validate the token
255                         _name = _info.GetString ("m_name");
256                         if (_name != null) {
257                                 // validate token by comparing names
258                                 string name = GetTokenName (_token);
259                                 if (name != _name)
260                                         throw new SerializationException ("Token-Name mismatch.");
261                         }
262                         else {
263                                 // validate token by getting name
264                                 _name = GetTokenName (_token);
265                                 if (_name == null)
266                                         throw new SerializationException ("Token doesn't match a user.");
267                         }
268                         _type = _info.GetString ("m_type");
269                         _account = (WindowsAccountType) _info.GetValue ("m_acctType", typeof (WindowsAccountType));
270                         _authenticated = _info.GetBoolean ("m_isAuthenticated");
271                 }
272
273                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) 
274                 {
275                         info.AddValue ("m_userToken", _token);
276                         // can be null when not resolved
277                         info.AddValue ("m_name", _name);
278                         info.AddValue ("m_type", _type);
279                         info.AddValue ("m_acctType", _account);
280                         info.AddValue ("m_isAuthenticated", _authenticated);
281                 }
282
283                 internal ClaimsIdentity CloneAsBase ()
284                 {
285                         return base.Clone();
286                 }
287
288                 internal IntPtr GetTokenInternal ()
289                 {
290                         return _token;
291                 }
292
293                 private void SetToken (IntPtr token) 
294                 {
295                         if (Environment.IsUnix) {
296
297                                 _token = token;
298                                 // apply defaults
299                                 if (_type == null)
300                                         _type = "POSIX";
301                                 // override user choice in this specific case
302                                 if (_token == IntPtr.Zero)
303                                         _account = WindowsAccountType.System;
304                         }
305                         else {
306                                 if ((token == invalidWindows) && (_account != WindowsAccountType.Anonymous))
307                                         throw new ArgumentException ("Invalid token");
308
309                                 _token = token;
310                                 // apply defaults
311                                 if (_type == null)
312                                         _type = "NTLM";
313                         }
314                 }
315
316                 public SafeAccessTokenHandle AccessToken {
317                         get { throw new NotImplementedException (); }
318                 }
319
320                 // see mono/mono/metadata/security.c for implementation
321
322                 // Many people use reflection to get a user's roles - so many 
323                 // that's it's hard to say it's an "undocumented" feature -
324                 // so we also implement it in Mono :-/
325                 // http://www.dotnet247.com/247reference/msgs/39/195403.aspx
326                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
327                 internal extern static string[] _GetRoles (IntPtr token);
328
329                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
330                 internal extern static IntPtr GetCurrentToken ();
331
332                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
333                 private extern static string GetTokenName (IntPtr token);
334
335                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
336                 private extern static IntPtr GetUserToken (string username);
337         }
338 }