Merge pull request #1032 from miguelzf/master
[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
37 namespace System.Security.Principal {
38
39         [Serializable]
40         [ComVisible (true)]
41         public class WindowsIdentity :
42 #if NET_4_5
43         System.Security.Claims.ClaimsIdentity,
44 #endif
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                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
56                 public WindowsIdentity (IntPtr userToken) 
57                         : this (userToken, null, WindowsAccountType.Normal, false)
58                 {
59                 }
60
61                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
62                 public WindowsIdentity (IntPtr userToken, string type) 
63                         : this (userToken, type, WindowsAccountType.Normal, false)
64                 {
65                 }
66
67                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
68                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType)
69                         : this (userToken, type, acctType, false)
70                 {
71                 }
72
73                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
74                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
75                 {
76                         _type = type;
77                         _account = acctType;
78                         _authenticated = isAuthenticated;
79                         _name = null;
80                         // last - as it can override some fields
81                         SetToken (userToken);
82                 }
83
84                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
85                 public WindowsIdentity (string sUserPrincipalName) 
86                         : this (sUserPrincipalName, null)
87                 {
88                 }
89
90                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
91                 public WindowsIdentity (string sUserPrincipalName, string type)
92                 {
93                         if (sUserPrincipalName == null)
94                                 throw new NullReferenceException ("sUserPrincipalName");
95
96                         // TODO: Windows 2003 compatibility should be done in runtime
97                         IntPtr token = GetUserToken (sUserPrincipalName);
98                         if ((!Environment.IsUnix) && (token == IntPtr.Zero)) {
99                                 throw new ArgumentException ("only for Windows Server 2003 +");
100                         }
101
102                         _authenticated = true;
103                         _account = WindowsAccountType.Normal;
104                         _type = type;
105                         // last - as it can override some fields
106                         SetToken (token);
107                 }
108
109                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
110                 public WindowsIdentity (SerializationInfo info, StreamingContext context)
111                 {
112                         _info = info;
113                 }
114
115                 [ComVisible (false)]
116                 public void Dispose ()
117                 {
118                         _token = IntPtr.Zero;
119                 }
120                 
121                 [ComVisible (false)]
122                 protected virtual void Dispose (bool disposing)
123                 {
124                         _token = IntPtr.Zero;
125                 }
126                 // static methods
127
128                 public static WindowsIdentity GetAnonymous ()
129                 {
130                         WindowsIdentity id = null;
131                         if (Environment.IsUnix) {
132                                 id = new WindowsIdentity ("nobody");
133                                 // special case
134                                 id._account = WindowsAccountType.Anonymous;
135                                 id._authenticated = false;
136                                 id._type = String.Empty;
137                         }
138                         else {
139                                 id = new WindowsIdentity (IntPtr.Zero, String.Empty, WindowsAccountType.Anonymous, false);
140                                 // special case (don't try to resolve the name)
141                                 id._name = String.Empty;
142                         }
143                         return id;
144                 }
145
146                 public static WindowsIdentity GetCurrent ()
147                 {
148                         return new WindowsIdentity (GetCurrentToken (), null, WindowsAccountType.Normal, true);
149                 }
150                 [MonoTODO ("need icall changes")]
151                 public static WindowsIdentity GetCurrent (bool ifImpersonating)
152                 {
153                         throw new NotImplementedException ();
154                 }
155
156                 [MonoTODO ("need icall changes")]
157                 public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess)
158                 {
159                         throw new NotImplementedException ();
160                 }
161                 // methods
162
163                 public virtual WindowsImpersonationContext Impersonate ()
164                 {
165                         return new WindowsImpersonationContext (_token);
166                 }
167
168                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
169                 public static WindowsImpersonationContext Impersonate (IntPtr userToken)
170                 {
171                         return new WindowsImpersonationContext (userToken);
172                 }
173
174                 // properties
175 #if NET_4_5
176                 sealed override
177 #endif
178                 public string AuthenticationType {
179                         get { return _type; }
180                 }
181
182                 public virtual bool IsAnonymous
183                 {
184                         get { return (_account == WindowsAccountType.Anonymous); }
185                 }
186
187 #if NET_4_5
188                 override
189 #else
190                 virtual
191 #endif
192                 public bool IsAuthenticated
193                 {
194                         get { return _authenticated; }
195                 }
196
197                 public virtual bool IsGuest
198                 {
199                         get { return (_account == WindowsAccountType.Guest); }
200                 }
201
202                 public virtual bool IsSystem
203                 {
204                         get { return (_account == WindowsAccountType.System); }
205                 }
206
207 #if NET_4_5
208                 override
209 #else
210                 virtual
211 #endif
212                 public string Name
213                 {
214                         get {
215                                 if (_name == null) {
216                                         // revolve name (runtime)
217                                         _name = GetTokenName (_token);
218                                 }
219                                 return _name; 
220                         }
221                 }
222
223                 public virtual IntPtr Token
224                 {
225                         get { return _token; }
226                 }
227                 [MonoTODO ("not implemented")]
228                 public IdentityReferenceCollection Groups {
229                         get { throw new NotImplementedException (); }
230                 }
231
232                 [MonoTODO ("not implemented")]
233                 [ComVisible (false)]
234                 public TokenImpersonationLevel ImpersonationLevel {
235                         get { throw new NotImplementedException (); }
236                 }
237
238                 [MonoTODO ("not implemented")]
239                 [ComVisible (false)]
240                 public SecurityIdentifier Owner {
241                         get { throw new NotImplementedException (); }
242                 }
243
244                 [MonoTODO ("not implemented")]
245                 [ComVisible (false)]
246                 public SecurityIdentifier User {
247                         get { throw new NotImplementedException (); }
248                 }
249                 void IDeserializationCallback.OnDeserialization (object sender)
250                 {
251                         _token = (IntPtr) _info.GetValue ("m_userToken", typeof (IntPtr));
252                         // can't trust this alone - we must validate the token
253                         _name = _info.GetString ("m_name");
254                         if (_name != null) {
255                                 // validate token by comparing names
256                                 string name = GetTokenName (_token);
257                                 if (name != _name)
258                                         throw new SerializationException ("Token-Name mismatch.");
259                         }
260                         else {
261                                 // validate token by getting name
262                                 _name = GetTokenName (_token);
263                                 if (_name == null)
264                                         throw new SerializationException ("Token doesn't match a user.");
265                         }
266                         _type = _info.GetString ("m_type");
267                         _account = (WindowsAccountType) _info.GetValue ("m_acctType", typeof (WindowsAccountType));
268                         _authenticated = _info.GetBoolean ("m_isAuthenticated");
269                 }
270
271                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) 
272                 {
273                         info.AddValue ("m_userToken", _token);
274                         // can be null when not resolved
275                         info.AddValue ("m_name", _name);
276                         info.AddValue ("m_type", _type);
277                         info.AddValue ("m_acctType", _account);
278                         info.AddValue ("m_isAuthenticated", _authenticated);
279                 }
280
281                 private void SetToken (IntPtr token) 
282                 {
283                         if (Environment.IsUnix) {
284
285                                 _token = token;
286                                 // apply defaults
287                                 if (_type == null)
288                                         _type = "POSIX";
289                                 // override user choice in this specific case
290                                 if (_token == IntPtr.Zero)
291                                         _account = WindowsAccountType.System;
292                         }
293                         else {
294                                 if ((token == invalidWindows) && (_account != WindowsAccountType.Anonymous))
295                                         throw new ArgumentException ("Invalid token");
296
297                                 _token = token;
298                                 // apply defaults
299                                 if (_type == null)
300                                         _type = "NTLM";
301                         }
302                 }
303
304                 // see mono/mono/metadata/security.c for implementation
305
306                 // Many people use reflection to get a user's roles - so many 
307                 // that's it's hard to say it's an "undocumented" feature -
308                 // so we also implement it in Mono :-/
309                 // http://www.dotnet247.com/247reference/msgs/39/195403.aspx
310                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
311                 internal extern static string[] _GetRoles (IntPtr token);
312
313                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
314                 internal extern static IntPtr GetCurrentToken ();
315
316                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
317                 private extern static string GetTokenName (IntPtr token);
318
319                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
320                 private extern static IntPtr GetUserToken (string username);
321         }
322 }