|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// <OWNER>Microsoft</OWNER>
namespace System.Security.Principal
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Security.Permissions;
[System.Runtime.InteropServices.ComVisible(false)]
public class IdentityReferenceCollection : ICollection<IdentityReference>
{
#region Private members
//
// Container enumerated by this collection
//
private List<IdentityReference> _Identities;
#endregion
#region Constructors
//
// Creates an empty collection of default size
//
public IdentityReferenceCollection()
: this( 0 )
{
}
//
// Creates an empty collection of given initial size
//
public IdentityReferenceCollection( int capacity )
{
_Identities = new List<IdentityReference>( capacity );
}
#endregion
#region ICollection<IdentityReference> implementation
public void CopyTo( IdentityReference[] array, int offset )
{
_Identities.CopyTo( 0, array, offset, Count );
}
public int Count
{
get { return _Identities.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public void Add( IdentityReference identity )
{
if ( identity == null )
{
throw new ArgumentNullException( "identity" );
}
Contract.EndContractBlock();
_Identities.Add( identity );
}
public bool Remove( IdentityReference identity )
{
if ( identity == null )
{
throw new ArgumentNullException( "identity" );
}
Contract.EndContractBlock();
if ( Contains( identity ))
{
_Identities.Remove( identity );
return true;
}
return false;
}
public void Clear()
{
_Identities.Clear();
}
public bool Contains( IdentityReference identity )
{
if ( identity == null )
{
throw new ArgumentNullException( "identity" );
}
Contract.EndContractBlock();
return _Identities.Contains( identity );
}
#endregion
#region IEnumerable<IdentityReference> implementation
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<IdentityReference> GetEnumerator()
{
return new IdentityReferenceEnumerator( this );
}
#endregion
#region Public methods
public IdentityReference this[int index]
{
get
{
return _Identities[index];
}
set
{
if ( value == null )
{
throw new ArgumentNullException( "value" );
}
Contract.EndContractBlock();
_Identities[index] = value;
}
}
internal List<IdentityReference> Identities
{
get { return _Identities; }
}
public IdentityReferenceCollection Translate( Type targetType )
{
return Translate( targetType, false );
}
[SecuritySafeCritical]
[SecurityPermission(SecurityAction.Demand, ControlPrincipal = true)]
public IdentityReferenceCollection Translate( Type targetType, bool forceSuccess )
{
if ( targetType == null )
{
throw new ArgumentNullException( "targetType" );
}
//
// Target type must be a subclass of IdentityReference
//
if ( !targetType.IsSubclassOf( typeof( IdentityReference )))
{
throw new ArgumentException( Environment.GetResourceString( "IdentityReference_MustBeIdentityReference" ), "targetType" );
}
Contract.EndContractBlock();
//
// if the source collection is empty, just return an empty collection
//
if (Identities.Count == 0)
{
return new IdentityReferenceCollection();
}
int SourceSidsCount = 0;
int SourceNTAccountsCount = 0;
//
// First, see how many of each of the source types we have.
// The cases where source type == target type require no conversion.
//
for ( int i = 0; i < Identities.Count; i++ )
{
Type type = Identities[i].GetType();
if ( type == targetType )
{
continue;
}
else if ( type == typeof( SecurityIdentifier ))
{
SourceSidsCount += 1;
}
else if ( type == typeof( NTAccount ))
{
SourceNTAccountsCount += 1;
}
else
{
//
// Rare case that we have defined a type of identity reference and
// not included it in the code logic above (this is more like a bug in the implementation
// but only as long as we do not allow IdentityReference to be subclassed outside of the BCL)
//
Contract.Assert( false, "Source type is an IdentityReference type which has not been included in translation logic.");
throw new SystemException();
}
}
bool Homogeneous = false;
IdentityReferenceCollection SourceSids = null;
IdentityReferenceCollection SourceNTAccounts = null;
if ( SourceSidsCount == Count )
{
Homogeneous = true;
SourceSids = this;
}
else if ( SourceSidsCount > 0 )
{
SourceSids = new IdentityReferenceCollection( SourceSidsCount );
}
if ( SourceNTAccountsCount == Count )
{
Homogeneous = true;
SourceNTAccounts = this;
}
else if ( SourceNTAccountsCount > 0 )
{
SourceNTAccounts = new IdentityReferenceCollection( SourceNTAccountsCount );
}
//
// Repackage only if the source is not homogeneous (contains different source types)
//
IdentityReferenceCollection Result = null;
if ( !Homogeneous )
{
Result = new IdentityReferenceCollection( Identities.Count );
for ( int i = 0; i < Identities.Count; i++ )
{
IdentityReference id = this[i];
Type type = id.GetType();
if ( type == targetType )
{
continue;
}
else if ( type == typeof( SecurityIdentifier ))
{
SourceSids.Add( id );
}
else if ( type == typeof( NTAccount ))
{
SourceNTAccounts.Add( id );
}
else
{
//
// Rare case that we have defined a type of identity reference and
// not included it in the code logic above (this is more like a bug in the implementation
// but only as long as we do not allow IdentityReference to be subclassed outside of the BCL)
//
Contract.Assert( false, "Source type is an IdentityReference type which has not been included in translation logic.");
throw new SystemException();
}
}
}
bool someFailed = false;
IdentityReferenceCollection TargetSids = null, TargetNTAccounts = null;
if ( SourceSidsCount > 0 )
{
TargetSids = SecurityIdentifier.Translate( SourceSids, targetType, out someFailed );
if ( Homogeneous && !(forceSuccess && someFailed))
{
Result = TargetSids;
}
}
if ( SourceNTAccountsCount > 0 )
{
TargetNTAccounts = NTAccount.Translate( SourceNTAccounts, targetType, out someFailed );
if ( Homogeneous && !(forceSuccess && someFailed))
{
Result = TargetNTAccounts;
}
}
if (forceSuccess && someFailed) {
//
// Need to throw an exception here and provide information regarding
// which identity references could not be translated to the target type
//
Result = new IdentityReferenceCollection();
if (TargetSids != null) {
foreach (IdentityReference id in TargetSids) {
if ( id.GetType() != targetType )
{
Result.Add(id);
}
}
}
if (TargetNTAccounts != null) {
foreach (IdentityReference id in TargetNTAccounts) {
if ( id.GetType() != targetType )
{
Result.Add(id);
}
}
}
throw new IdentityNotMappedException( Environment.GetResourceString("IdentityReference_IdentityNotMapped"), Result);
}
else if ( !Homogeneous )
{
SourceSidsCount = 0;
SourceNTAccountsCount = 0;
Result = new IdentityReferenceCollection( Identities.Count );
for ( int i = 0; i < Identities.Count; i++ )
{
IdentityReference id = this[i];
Type type = id.GetType();
if ( type == targetType )
{
Result.Add( id );
}
else if ( type == typeof( SecurityIdentifier ))
{
Result.Add( TargetSids[SourceSidsCount++] );
}
else if ( type == typeof( NTAccount ))
{
Result.Add( TargetNTAccounts[SourceNTAccountsCount++] );
}
else
{
//
// Rare case that we have defined a type of identity reference and
// not included it in the code logic above (this is more like a bug in the implementation
// but only as long as we do not allow IdentityReference to be subclassed outside of the BCL)
//
Contract.Assert( false, "Source type is an IdentityReference type which has not been included in translation logic.");
throw new SystemException();
}
}
}
return Result;
}
#endregion
}
[System.Runtime.InteropServices.ComVisible(false)]
internal class IdentityReferenceEnumerator : IEnumerator<IdentityReference>, IDisposable
{
#region Private members
//
// Current enumeration index
//
private int _Current;
//
// Parent collection
//
private readonly IdentityReferenceCollection _Collection;
#endregion
#region Constructors
internal IdentityReferenceEnumerator( IdentityReferenceCollection collection )
{
if ( collection == null )
{
throw new ArgumentNullException( "collection" );
}
Contract.EndContractBlock();
_Collection = collection;
_Current = -1;
}
#endregion
#region IEnumerator implementation
/// <internalonly/>
object IEnumerator.Current
{
get { return _Collection.Identities[_Current]; }
}
public IdentityReference Current
{
get { return (( IEnumerator )this).Current as IdentityReference; }
}
public bool MoveNext()
{
_Current++;
return ( _Current < _Collection.Count );
}
public void Reset()
{
_Current = -1;
}
public void Dispose()
{
}
#endregion
}
}
|