Merge pull request #1179 from ludovic-henry/pr25-threadpool
[mono.git] / mcs / class / System.Web / System.Web.Security / RolePrincipal.cs
index 052d6c80282cde4d914019c9a59e8b4a61c46331..b210f8274765a079709791812c9a109135b0eadc 100644 (file)
 //
 // Authors:
 //     Ben Maurer (bmaurer@users.sourceforge.net)
+//     Sebastien Pouliot  <sebastien@ximian.com>
 //
 // (C) 2003 Ben Maurer
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_2_0
-using System.Collections;
 using System.Collections.Specialized;
-using System.Text;
-using System.Security;
+using System.Security.Permissions;
 using System.Security.Principal;
+using System.Web.Configuration;
+using System.Web.Util;
+using System.IO;
+using System.Text;
 
 namespace System.Web.Security {
-       public sealed class RolePrincipal : IPrincipal {
-               
-               [MonoTODO]
-               public RolePrincipal ()
+
+       [Serializable]
+       [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+#if NET_4_0
+       public
+#else
+       public sealed
+#endif
+       class RolePrincipal : IPrincipal {
+
+               IIdentity _identity;
+               bool _listChanged;
+               string[] _cachedArray;
+               HybridDictionary _cachedRoles;
+               readonly string _providerName;
+
+               int _version = 1;
+               string _cookiePath;
+               DateTime _issueDate;
+               DateTime _expireDate;
+
+
+               public RolePrincipal (IIdentity identity)
                {
-                       throw new NotImplementedException ();
+                       if (identity == null)
+                               throw new ArgumentNullException ("identity");
+                       
+                       this._identity = identity;
+                       this._cookiePath = RoleManagerConfig.CookiePath;
+                       this._issueDate = DateTime.Now;
+                       this._expireDate = _issueDate.Add (RoleManagerConfig.CookieTimeout);
                }
-               
-               [MonoTODO]
-               public RolePrincipal (bool createFromCookie)
+
+               public RolePrincipal (IIdentity identity, string encryptedTicket)
+                       : this (identity)
                {
-                       throw new NotImplementedException ();
+                       DecryptTicket (encryptedTicket);
                }
-               
-               [MonoTODO]
-               public RolePrincipal (string encryptedTicket)
+
+               public RolePrincipal (string providerName, IIdentity identity)
+                       : this (identity)
                {
-                       throw new NotImplementedException ();
+                       if (providerName == null)
+                               throw new ArgumentNullException ("providerName");
+
+                       this._providerName = providerName;
                }
-               
-               [MonoTODO]
-               public string [] GetRoles ()
+
+               public RolePrincipal (string providerName, IIdentity identity, string encryptedTicket)
+                       : this (providerName, identity)
                {
-                       throw new NotImplementedException ();
+                       DecryptTicket (encryptedTicket);
                }
-               
-               [MonoTODO]
-               public void Init ()
+
+               public string [] GetRoles ()
                {
-                       throw new NotImplementedException ();
+                       if (!_identity.IsAuthenticated)
+                               return new string[0];
+
+                       if (!IsRoleListCached || Expired) {
+                               _cachedArray = Provider.GetRolesForUser (_identity.Name);
+                               _cachedRoles = new HybridDictionary (true);
+
+                               foreach (string r in _cachedArray)
+                                       _cachedRoles.Add(r, r);
+
+                               _listChanged = true;
+                       }
+
+                       return _cachedArray;
                }
                
-               [MonoTODO]
-               public void InitFromCookie (string cookieName)
+               public bool IsInRole (string role)
                {
-                       throw new NotImplementedException ();
+                       if (!_identity.IsAuthenticated)
+                               return false;
+
+                       GetRoles ();
+
+                       return _cachedRoles [role] != null;
                }
                
-               [MonoTODO]
-               public void InitFromEncryptedTicket (string strTicket)
+               public string ToEncryptedTicket ()
                {
-                       throw new NotImplementedException ();
-               }
+                       string roles = string.Join (",", GetRoles ());
+                       string cookiePath = RoleManagerConfig.CookiePath;
+                       int approxTicketLen = roles.Length + cookiePath.Length + 64;
+
+                       if (_cachedArray.Length > Roles.MaxCachedResults)
+                              return null;
+
+                       MemoryStream ticket = new MemoryStream (approxTicketLen);
+                       BinaryWriter writer = new BinaryWriter (ticket);
+
+                       // version
+                       writer.Write (Version);
                
-               [MonoTODO]
-               public bool IsInRole (string role)
+                       // issue datetime
+                       DateTime issueDate = DateTime.Now;
+                       writer.Write (issueDate.Ticks);
+
+                       // expiration datetime
+                       writer.Write (_expireDate.Ticks);
+
+                       writer.Write (cookiePath);
+                       writer.Write (roles);
+
+                       CookieProtection cookieProtection = RoleManagerConfig.CookieProtection;
+
+                       byte[] ticket_data = ticket.GetBuffer ();
+                       if (cookieProtection == CookieProtection.All) {
+                               ticket_data = MachineKeySectionUtils.EncryptSign (MachineConfig, ticket_data);
+                       } else if (cookieProtection == CookieProtection.Encryption) {
+                               ticket_data = MachineKeySectionUtils.Encrypt (MachineConfig, ticket_data);
+                       } else if (cookieProtection == CookieProtection.Validation) {
+                               ticket_data = MachineKeySectionUtils.Sign (MachineConfig, ticket_data);
+                       }
+
+                       return GetBase64FromBytes (ticket_data, 0, ticket_data.Length);
+               }
+
+               void DecryptTicket (string encryptedTicket)
                {
-                       throw new NotImplementedException ();
+                       if (encryptedTicket == null || encryptedTicket == String.Empty)
+                               throw new ArgumentException ("Invalid encrypted ticket", "encryptedTicket");
+
+                       byte [] ticketBytes = GetBytesFromBase64 (encryptedTicket);
+                       byte [] decryptedTicketBytes = null;
+
+                       CookieProtection cookieProtection = RoleManagerConfig.CookieProtection;
+
+                       if (cookieProtection == CookieProtection.All) {
+                               decryptedTicketBytes = MachineKeySectionUtils.VerifyDecrypt (MachineConfig, ticketBytes);
+                       } else if (cookieProtection == CookieProtection.Encryption) {
+                               decryptedTicketBytes = MachineKeySectionUtils.Decrypt (MachineConfig, ticketBytes);
+                       } else if (cookieProtection == CookieProtection.Validation) {
+                               decryptedTicketBytes = MachineKeySectionUtils.Verify (MachineConfig, ticketBytes);
+                       }
+
+                       if (decryptedTicketBytes == null)
+                               throw new HttpException ("ticket validation failed");
+
+                       MemoryStream ticket = new MemoryStream (decryptedTicketBytes);
+                       BinaryReader reader = new BinaryReader (ticket);
+
+                       // version
+                       _version = reader.ReadInt32 ();
+
+                       // issued date
+                       _issueDate = new DateTime (reader.ReadInt64 ());
+
+                       // expire date
+                       _expireDate = new DateTime (reader.ReadInt64 ());
+
+                       // cookie path
+                       _cookiePath = reader.ReadString ();
+                       
+                       // roles
+                       string roles = reader.ReadString ();
+
+                       if (!Expired) {
+                               InitializeRoles (roles);
+                               //update ticket if less than half of CookieTimeout remaining.
+                               if (Roles.CookieSlidingExpiration){
+                                       if (_expireDate-DateTime.Now < TimeSpan.FromTicks (RoleManagerConfig.CookieTimeout.Ticks/2))    {
+                                               _issueDate = DateTime.Now;
+                                               _expireDate = DateTime.Now.Add (RoleManagerConfig.CookieTimeout);
+                                               SetDirty ();
+                                       }
+                               }
+                       } else {
+                               // issue a new ticket
+                               _issueDate = DateTime.Now;
+                               _expireDate = _issueDate.Add (RoleManagerConfig.CookieTimeout);
+                       }
                }
-               
-               [MonoTODO]
-               public string ToEncryptedTicket ()
+
+               void InitializeRoles (string decryptedRoles)
                {
-                       throw new NotImplementedException ();
+                       _cachedArray = decryptedRoles.Split (',');
+                       _cachedRoles = new HybridDictionary (true);
+
+                       foreach (string r in _cachedArray)
+                               _cachedRoles.Add (r, r);
                }
-               
-               [MonoTODO]
+
                public bool CachedListChanged {
-                       get { throw new NotImplementedException (); }
+                       get { return _listChanged; }
                }
                
-               [MonoTODO]
                public string CookiePath {
-                       get { throw new NotImplementedException (); }
+                       get { return _cookiePath; }
                }
                
-               [MonoTODO]
                public bool Expired {
-                       get { throw new NotImplementedException (); }
+                       get { return ExpireDate < DateTime.Now; }
                }
                
-               [MonoTODO]
                public DateTime ExpireDate {
-                       get { throw new NotImplementedException (); }
+                       get { return _expireDate; }
                }
                
-               [MonoTODO]
                public IIdentity Identity {
-                       get { throw new NotImplementedException (); }
+                       get { return _identity; }
                }
                
-               [MonoTODO]
                public bool IsRoleListCached {
-                       get { throw new NotImplementedException (); }
+                       get { return (_cachedRoles != null) && RoleManagerConfig.CacheRolesInCookie; }
                }
                
-               [MonoTODO]
                public DateTime IssueDate {
-                       get { throw new NotImplementedException (); }
+                       get { return _issueDate; }
                }
                
-               [MonoTODO]
-               public string UserData {
-                       get { throw new NotImplementedException (); }
+               public string ProviderName {
+                       get { return String.IsNullOrEmpty(_providerName) ? Provider.Name : _providerName; }
                }
                
-               [MonoTODO]
                public int Version {
-                       get { throw new NotImplementedException (); }
+                       get { return _version; }
+               }
+
+               RoleProvider Provider {
+                       get {
+                               if (String.IsNullOrEmpty (_providerName))
+                                       return Roles.Provider;
+
+                               return Roles.Providers [_providerName];
+                       }
+               }
+
+               public void SetDirty ()
+               {
+                       _listChanged = true;
+                       _cachedRoles = null;
+                       _cachedArray = null;
+               }
+
+               static string GetBase64FromBytes (byte [] bytes, int offset, int len)
+               {
+                       return Convert.ToBase64String (bytes, offset, len);
+               }
+
+               static byte [] GetBytesFromBase64 (string base64String)
+               {
+                       return Convert.FromBase64String (base64String);
+               }
+
+               RoleManagerSection RoleManagerConfig
+               {
+                       get { return (RoleManagerSection) WebConfigurationManager.GetSection ("system.web/roleManager"); }
+               }
+
+               MachineKeySection MachineConfig
+               {
+                       get { return (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey"); }
                }
        }
 }
-#endif
+