File: Base\System\Security\RightsManagement\User.cs
Project: wpf\src\WindowsBase.csproj (WindowsBase)
//-----------------------------------------------------------------------------
//
// <copyright file="User.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description:
//  This class implements the UnsignedPublishLicense class 
//   this class is the first step in the RightsManagement publishing process
//
// History:
//  06/01/2005: IgorBel :   Initial Implementation 
//
//-----------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Collections.Generic;           // for IEqualityComparer<T> generic interface.
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Windows;
 
using MS.Internal;                          // for Invariant
using MS.Internal.Security.RightsManagement;
using SecurityHelper = MS.Internal.WindowsBase.SecurityHelper;
 
namespace System.Security.RightsManagement
{
 
    /// <summary>
    ///  This class represents a User for purposes of granting rights to that user, initializing secure environment for the user, 
    /// or enumerating rights granted to various users. 
    /// </summary>
    /// <SecurityNote>
    ///     Critical:    This class expose access to methods that eventually do one or more of the the following
    ///             1. call into unmanaged code 
    ///             2. affects state/data that will eventually cross over unmanaged code boundary
    ///             3. Return some RM related information which is considered private 
    ///
    ///     TreatAsSafe: This attrbiute automatically applied to all public entry points. All the public entry points have
    ///     Demands for RightsManagementPermission at entry to counter the possible attacks that do 
    ///     not lead to the unamanged code directly(which is protected by another Demand there) but rather leave 
    ///     some status/data behind which eventually might cross the unamanaged boundary. 
    /// </SecurityNote>
    [SecurityCritical(SecurityCriticalScope.Everything)]
    public class ContentUser
    {
        /// <summary>
        ///  This constructor creates a user that will be granted a right. Or used in other related scenarios like
        /// initializing secure environment for the user, or enumerating rights granted to various users.         
        /// </summary>
        public ContentUser(string name, AuthenticationType authenticationType)
        {
            SecurityHelper.DemandRightsManagementPermission();
 
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
 
            if (name.Trim().Length == 0)
            {
                throw new ArgumentOutOfRangeException("name");
            }
 
            if ((authenticationType != AuthenticationType.Windows) &&
                (authenticationType != AuthenticationType.Passport) &&
                (authenticationType != AuthenticationType.WindowsPassport) &&
                (authenticationType != AuthenticationType.Internal))
            {
                throw new ArgumentOutOfRangeException("authenticationType");
            }
 
            // We only support Anyone for the internal mode at the moment
            if (authenticationType == AuthenticationType.Internal)
            {
                if (!CompareToAnyone(name) && !CompareToOwner(name))
                {
                    // we only support Anyone as internal user 
                    throw new ArgumentOutOfRangeException("name");
                }
            }
 
            _name = name;
            _authenticationType = authenticationType;
        }
 
        /// <summary>
        /// Currently only 2 Authentication types supported Windows and Passport
        /// </summary>
        public AuthenticationType AuthenticationType
        {
            get
            {
                SecurityHelper.DemandRightsManagementPermission();
 
                return _authenticationType;
            }
        }
 
        /// <summary>
        /// Fully qualified SMTP address.
        /// </summary>
        public string Name
        {
            get
            {
                SecurityHelper.DemandRightsManagementPermission();
 
                return _name;
            }
        }
 
        /// <summary>
        /// Return true if the current User currently authenticated, which means that initialization 
        /// process will likely not require a prompt.
        /// We check if the machine and the user are activated.
        /// We don't check the existence of a client licensor certificate since it is only
        ///     required for publishing only
        /// </summary>
        public bool IsAuthenticated()
        {
            SecurityHelper.DemandRightsManagementPermission();
 
            // we can only have activated Windows or Passport users 
            // undefined authentication type can only be used for building a UnsignedPublishLicense  
            if ((_authenticationType != AuthenticationType.Windows) &&
                 (_authenticationType != AuthenticationType.Passport))
            {
                return false;
            }
 
            // User specific client session to check it's status 
            using (ClientSession userClientSession = new ClientSession(this))
            {
                return (userClientSession.IsMachineActivated() &&
                                userClientSession.IsUserActivated());
            }
        }
 
        /// <summary>
        /// Test for equality.
        /// </summary>
        public override bool Equals(object obj)
        {
            SecurityHelper.DemandRightsManagementPermission();
 
            if (obj == null)
                return false;   // Standard behavior.
 
            if (GetType() != obj.GetType())
                return false;   // Different type.
 
            ContentUser userObj = (ContentUser)obj;
 
            return (String.CompareOrdinal(_name.ToUpperInvariant(), userObj._name.ToUpperInvariant()) == 0)
                        &&
                            _authenticationType.Equals(userObj._authenticationType);
        }
 
        /// <summary>
        /// Returns an instance of the User class that identifyes "Anyone" persona.
        /// This user has authentication type "Internal" and Name "Anyone".
        /// If this such user was granted rights dutring publishing; server will issue Use License 
        /// to anyone who requests one, but it will be attached to the requesting user.  
        /// </summary>
        public static ContentUser AnyoneUser
        {
            get
            {
                SecurityHelper.DemandRightsManagementPermission();
 
                if (_anyoneUser == null)
                {
                    _anyoneUser = new ContentUser(AnyoneUserName, AuthenticationType.Internal);
                }
                return _anyoneUser;
            }
        }
 
        /// <summary>
        /// Returns an instance of the User class that identifies "Owner" persona.
        /// This user has authentication type Internal and Name "Owner".
        /// This is mostly used by the server side templates to give special rights to the 
        /// Publisher/author who would be building a protected document using those templates
        /// </summary>
        public static ContentUser OwnerUser
        {
            get
            {
                SecurityHelper.DemandRightsManagementPermission();
 
                if (_ownerUser == null)
                {
                    _ownerUser = new ContentUser(OwnerUserName, AuthenticationType.Internal);
                }
                return _ownerUser;
            }
        }
 
        /// <summary>
        /// Compute hash code.
        /// </summary>
        public override int GetHashCode()
        {
            SecurityHelper.DemandRightsManagementPermission();
 
            if (!hashCalcIsDone)
            {
                StringBuilder hashString = new StringBuilder(_name.ToUpperInvariant());
                hashString.Append(_authenticationType.ToString());
 
                hashValue = (hashString.ToString()).GetHashCode();
                hashCalcIsDone = true;
            }
 
            return hashValue;
        }
 
        /// <summary>
        /// Converts  AuthenticationType to AuthenticationProviderType string require for a client session 
        /// </summary>
        internal string AuthenticationProviderType
        {
            get
            {
                if (_authenticationType == AuthenticationType.Windows)
                {
                    return WindowsAuthProvider;
                }
                else if (_authenticationType == AuthenticationType.Passport)
                {
                    return PassportAuthProvider;
                }
                else
                {
                    Invariant.Assert(false, "AuthenticationProviderType can only be queried for Windows or Passport authentication");
                    return null;
                }
            }
        }
 
        /// <summary>
        /// Generic test for equality. This method allows any types based on ContentUser
        /// to be comparable.
        /// </summary>
        /// <SecurityNote>
        ///     TreatAsSafe: This method may be called indirectly from a Partial Trust environment. 
        ///         It only performs a safe string comparison.
        /// </SecurityNote>
        [SecurityTreatAsSafe]
        internal bool GenericEquals(ContentUser userObj)
        {
            // this checks for null argument
            if (userObj == null)
            {
                return false;
            }
            else
            {
                return (String.CompareOrdinal(_name.ToUpperInvariant(), userObj._name.ToUpperInvariant()) == 0)
                            &&
                                _authenticationType.Equals(userObj._authenticationType);
            }
        }
 
        /// <summary>
        /// Implements the IEqualityComparer generic interface to be
        /// used in a Dictionary with ContentUser as key type. 
        /// This interface allows any types based on ContentUser to be
        /// comparable.
        /// </summary>
        /// <SecurityNote>
        ///     TreatAsSafe: The methods of this class may be called indirectly from 
        ///                  a Partial Trust environment. 
        ///         Both methods only validate their parameters, then call other safe methods.
        /// </SecurityNote>
        [SecurityTreatAsSafe]
        internal sealed class ContentUserComparer : IEqualityComparer<ContentUser>
        {
            bool IEqualityComparer<ContentUser>.Equals(ContentUser user1, ContentUser user2)
            {
                Invariant.Assert(user1 != null, "user1 should not be null");
                return user1.GenericEquals(user2);
            }
 
            int IEqualityComparer<ContentUser>.GetHashCode(ContentUser user)
            {
                Invariant.Assert(user != null, "user should not be null");
                return user.GetHashCode();
            }
        }
 
        /// <summary>
        /// A comparer that can be passed to a Dictionary to allow
        /// generic match for different types based on ContentUser.
        /// </summary>
        /// <SecurityNote>
        ///     TreatAsSafe: This field will be accessed by SecurityTransparent code. It's static, readonly.
        ///             It's safe to allow access from SecurityTransparent code.
        /// </SecurityNote>
        [SecurityTreatAsSafe]
        internal static readonly ContentUserComparer _contentUserComparer = new ContentUserComparer();
 
        internal static bool CompareToAnyone(string name)
        {
            return (0 == String.CompareOrdinal(AnyoneUserName.ToUpperInvariant(), name.ToUpperInvariant()));
        }
 
        internal static bool CompareToOwner(string name)
        {
            return (0 == String.CompareOrdinal(OwnerUserName.ToUpperInvariant(), name.ToUpperInvariant()));
        }
 
        private const string WindowsAuthProvider = "WindowsAuthProvider";
        private const string PassportAuthProvider = "PassportAuthProvider";
 
        private const string OwnerUserName = "Owner";
        private static ContentUser _ownerUser;
 
        private const string AnyoneUserName = "Anyone";
        private static ContentUser _anyoneUser;
 
        private string _name;
        private AuthenticationType _authenticationType;
        private int hashValue;
        private bool hashCalcIsDone;    // flag that indicates the value in hasValue is already calculated and usable
    }
}