Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / SelfIssuedSamlTokenFactory.cs / 2 / SelfIssuedSamlTokenFactory.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace Microsoft.InfoCards { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.IdentityModel.Tokens; using System.IdentityModel.Selectors; using System.ServiceModel; using System.ServiceModel.Security; using System.ServiceModel.Security.Tokens; using System.Text; using System.Xml; using System.Globalization; using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; // // Summary: // Produces SamlTokens from the locally store claims. // internal class SelfIssuedSamlTokenFactory :TokenFactoryBase { public static readonly TimeSpan TokenLifetime = new TimeSpan( 1, 0, 0 );//1 hour static readonly SamlSerializer samlSerializer = new SamlSerializer(); // // Assertion ID must start with a letter or "_". // It cannot start with a digit. Neither should it contain a ":" // WCF uses "SamlSecurityToken-" as the prefix, doing the same here. // const string SamlAssertionIdPrefix = "SamlSecurityToken-"; // // DigestAlgorithm - for the basic algorithm suites, it is SHA1 // const string DefaultDigestAlgorithm = SecurityAlgorithms.Sha1Digest; // // SignatureAlgorithm - SHA1 unless speicified in RST template in recipient policy // string m_signatureAlgorithm = SecurityAlgorithms.RsaSha1Signature; // // EncryptionAlgorithm - AES 256 CBC unless speicified in RST template in recipient policy // string m_encryptionAlgorithm = SecurityAlgorithmSuite.Default.DefaultEncryptionAlgorithm; string m_encryptWithAlgorithm; string m_keyWrapAlgorithm; // // Summary: // Creates an instance of a SelfIssuedTokenFactory // Arguments: // connection: The store connection that the objects // are used from. // public SelfIssuedSamlTokenFactory() { } // // Summary: // Generates all token information. // // Arguments: // card: The infocard whos claims will be used. // creationParam: Creation parameters are not supported. This value must be null. // credential: This may contain a pin information, if the claims are pin protected. // policy: The policy of the recipient // // Return: // A new TokenDescriptor object containing the generated token information. // protected override TokenDescriptor ProduceToken( InfoCard card, TokenCreationParameter creationParam, TokenFactoryCredential credential, InfoCardPolicy policy, bool discloseOptional ) { Listclaims; XmlElement protectedToken; DisplayToken displayToken; SamlSecurityToken rawToken; RSACryptoServiceProvider proofKeyOnlyPublic = null; SymmetricAlgorithm sessionKey = null; SecurityKeyIdentifier identityKeyIdentifier; SecurityKeyIdentifier proofKeyIdentifier; SecurityKey proofCryptoInsideSamlToken; TokenDescriptor token; if( !String.IsNullOrEmpty( policy.OptionalRstParams.SignatureAlgorithm ) ) { // // If this is not supported, Indigo will throw // m_signatureAlgorithm = policy.OptionalRstParams.SignatureAlgorithm; } if( !String.IsNullOrEmpty( policy.OptionalRstParams.EncryptionAlgorithm ) ) { // // EncryptionUtility will throw if this is not supported. // m_encryptionAlgorithm = policy.OptionalRstParams.EncryptionAlgorithm; } // // We'll check signWith and encryptWith after setting the proof key // as it depends on the proof key type. // try { claims = GetClaimSet( card, policy, discloseOptional ); List disclosedClaims = new List ( claims.Count ); for( int i = 0; i < claims.Count; i++ ) { disclosedClaims.Add( claims[ i ].Id ); } // // Retrive the asymmetric public keys // using( RSACryptoServiceProvider identityKeyOnlyPublic = card.GetPublicCryptography( policy.Recipient.GetIdentifier() ) ) { identityKeyIdentifier = new SecurityKeyIdentifier( new RsaKeyIdentifierClause( identityKeyOnlyPublic ) ); // // Generate the proof key and identifier for the SAML subject. // This may be no key (browser case), symmetric, or asymmetric. // if( SecurityKeyTypeInternal.SymmetricKey == policy.KeyType ) { IDT.Assert( policy.ImmediateTokenRecipient is X509RecipientIdentity, "Symmetric key type is not allowed when no certifcate is provided for the token recipeint" ); m_keyWrapAlgorithm = SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm; IDT.Assert( "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" == m_keyWrapAlgorithm, "What we have chosen" ); if( !String.IsNullOrEmpty( policy.OptionalRstParams.EncryptWith ) ) { m_encryptWithAlgorithm = policy.OptionalRstParams.EncryptWith; } else { m_encryptWithAlgorithm = SecurityAlgorithmSuite.Default.DefaultEncryptionAlgorithm; } // // Encrypt the symmetric proof key using key wrap algorithm to the recipient's public key. // sessionKey = new RijndaelManaged(); // // Initialize the suite based on encrypt with so that we can get the // correct symmetric key size. // SecurityAlgorithmSuite suite; switch( m_encryptWithAlgorithm ) { case SecurityAlgorithms.Aes128Encryption: suite = SecurityAlgorithmSuite.Basic128; break; case SecurityAlgorithms.Aes192Encryption: suite = SecurityAlgorithmSuite.Basic192; break; case SecurityAlgorithms.Aes256Encryption: suite = SecurityAlgorithmSuite.Basic256; break; case SecurityAlgorithms.TripleDesEncryption: suite = SecurityAlgorithmSuite.TripleDes; break; default: throw IDT.ThrowHelperError( new TokenCreationException( SR.GetString( SR.UnsupportedEncryptWithAlgorithm, m_encryptWithAlgorithm ) ) ); } // // Now set the key size // sessionKey.KeySize = suite.DefaultSymmetricKeyLength; X509SecurityToken wrappingKey = new X509SecurityToken( ( ( X509RecipientIdentity ) policy.ImmediateTokenRecipient).LeafCertificate, Guid.NewGuid().ToString() ); SecurityKeyIdentifier wrappingKeyIdentifier = new SecurityKeyIdentifier( wrappingKey.CreateKeyIdentifierClause () ); byte[ ] wrappedKey = wrappingKey.SecurityKeys[ 0 ].EncryptKey( m_keyWrapAlgorithm, sessionKey.Key ); proofKeyIdentifier = new SecurityKeyIdentifier( new EncryptedKeyIdentifierClause( wrappedKey, m_keyWrapAlgorithm, wrappingKeyIdentifier ) ); // // Can't use proofKeyIdentifier.CreateKey() - otherwise we get InvalidOperationException // "This SecurityKeyIdentifier does not have any clause that can create a key. // proofCryptoInsideSamlToken = new InMemorySymmetricSecurityKey( sessionKey.Key ); ThrowIfProofKeyOperationsNotSupported( policy, proofCryptoInsideSamlToken ); } else if( SecurityKeyTypeInternal.AsymmetricKey == policy.KeyType ) { if( !String.IsNullOrEmpty( policy.OptionalRstParams.EncryptWith ) ) { m_encryptWithAlgorithm = policy.OptionalRstParams.EncryptWith; } else { m_encryptWithAlgorithm = SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm; } // // This is because RP will probably expect the same // key wrap for decrypting T and for decrypting the Message // m_keyWrapAlgorithm = m_encryptWithAlgorithm; sessionKey = null; // // Proof key, per infocard guide: // The subject confirmation key (proof key) specified in the self-issued token should be // treated as a short-term key that can be exercised by the service requester during the // token validity interval to demonstrate that it is the subject of the token. // So ideally, this should be proofKeyOnlyPublic = new RSACryptoServiceProvider( 1024 ); // In that case, also dispose that in the finally. // // However to prevent overhead of creating a temp RSA key pair, we are using the same public/private // key pair which is the identity key. So proofKeyOnlyPublic is just a dummy variable to illustrate // us passing in the proof key // proofKeyOnlyPublic = identityKeyOnlyPublic; proofKeyIdentifier = new SecurityKeyIdentifier( new RsaKeyIdentifierClause( proofKeyOnlyPublic ) ); proofCryptoInsideSamlToken = proofKeyIdentifier.CreateKey(); ThrowIfProofKeyOperationsNotSupported( policy, proofCryptoInsideSamlToken ); } else { m_keyWrapAlgorithm = SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm; IDT.Assert( "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" == m_keyWrapAlgorithm, "What we have chosen" ); IDT.Assert( SecurityKeyTypeInternal.NoKey == policy.KeyType, "Bad enum member for SecurityKeyTypeInternal." ); proofKeyIdentifier = null; proofCryptoInsideSamlToken = null; } using( SelfIssuedAuthAsymmetricKey issuerSigningKey = new SelfIssuedAuthAsymmetricKey( card.GetPrivateCryptography( policy.Recipient.GetIdentifier() ) ) ) { Uri recipient = policy.ImmediateTokenRecipient.Address.Uri; if( null != policy.PolicyAppliesTo ) { recipient = policy.PolicyAppliesTo.Uri; } // // Create the raw SAML token // rawToken = CreateSamlToken( claims, identityKeyIdentifier, proofKeyIdentifier, proofCryptoInsideSamlToken, issuerSigningKey, recipient ); displayToken = CreateDisplayToken( claims ); // // If the immediate token recipient specifies a certificate // then encrypt the token // X509RecipientIdentity x509Id = policy.ImmediateTokenRecipient as X509RecipientIdentity; if( null != x509Id ) { protectedToken = EncryptionUtility.EncryptSecurityToken( rawToken, x509Id.LeafCertificate, m_encryptionAlgorithm, m_keyWrapAlgorithm, policy.ProtocolVersionProfile ); } else { MemoryStream ms = new MemoryStream(); XmlDictionaryWriter xmlwriter = XmlDictionaryWriter.CreateDictionaryWriter( new XmlTextWriter( new StreamWriter( ms ) ) ); policy.ProtocolVersionProfile.TokenSerializer.WriteToken( xmlwriter, rawToken ); xmlwriter.Flush(); ms.Seek( 0, SeekOrigin.Begin ); XmlDocument doc = new XmlDocument(); protectedToken = (XmlElement)doc.ReadNode( Utility.CreateReaderWithQuotas( ms ) ); Array.Clear( ms.GetBuffer(), 0, Convert.ToInt32( ms.Length ) ); ms.Close(); } } } StringWriter writer = new StringWriter( CultureInfo.InvariantCulture ); policy.ProtocolVersionProfile.TokenSerializer.WriteKeyIdentifierClause( XmlDictionaryWriter.CreateDictionaryWriter( new XmlTextWriter( writer ) ), new SamlAssertionKeyIdentifierClause( rawToken.Id ) ); writer.Flush(); string tokenReference = writer.GetStringBuilder().ToString(); token = new TokenDescriptor( rawToken.Id, rawToken.ValidFrom, rawToken.ValidTo, protectedToken, displayToken, sessionKey, tokenReference, tokenReference, disclosedClaims ); // // Clear out references whose ownership has been transferred to the TokenDescriptor. // sessionKey = null; rawToken = null; } catch( InfoCardBaseException ) { // // Don't need to wrap this again // throw; } catch( Exception e ) { if( IDT.IsFatal( e ) ) { throw; } // // In case an asymmetric algorithm or some such is not supported and // SelfIssuedAuthRsaCryptoProvider throw a NotSuppotedException, which gets // wrapped by Indigo as InvalidOperationException // This could happen if the recipient specified a supported encryption algorithm // as a SIGNATURE algorithm -- This would pass the IsSupportedAlgorithm check but fail // when actually trying to generate the signature. // throw IDT.ThrowHelperError( new TokenCreationException( null, e ) ); } finally { // // Have to make certain that we dispose of the identity key before leaving if ownership wasn't // transferred to the TokenDescriptor. If we don't dispose of this then the finalizer will run and // throw since it will attempt to dispose as the wrong identity. // if( null != proofKeyOnlyPublic ) { // // This should already have been disposed since we are using the // same key for issuer and proof currently; just doing it for clarity // ( (IDisposable)proofKeyOnlyPublic ).Dispose(); proofKeyOnlyPublic = null; } if( null != sessionKey ) { ( (IDisposable)sessionKey ).Dispose(); sessionKey = null; } } return token; } void ThrowIfProofKeyOperationsNotSupported( InfoCardPolicy policy, SecurityKey proofCryptoInsideSamlToken ) { // // Check if the proof supports the SignWith algorithm URI. // if( !String.IsNullOrEmpty( policy.OptionalRstParams.SignWith ) && !proofCryptoInsideSamlToken.IsSupportedAlgorithm( policy.OptionalRstParams.SignWith ) ) { throw IDT.ThrowHelperError( new TokenCreationException( SR.GetString( SR.UnsupportedSignWithAlgorithm, policy.OptionalRstParams.SignWith ) ) ); } // // Check if the proof supports the EncryptWith algorithm URI. // if( !proofCryptoInsideSamlToken.IsSupportedAlgorithm( m_encryptWithAlgorithm ) ) { throw IDT.ThrowHelperError( new TokenCreationException( SR.GetString( SR.UnsupportedEncryptWithAlgorithm, m_encryptWithAlgorithm ) ) ); } } // // Summary: // Creates a new SamlSecurityToken object from the list of claims and the subject key. // // Arguments: // claims: The list of Claims to be converted to SamlAssertions. // identityKey: The derived key that will be used to identify the user. // // Returns: // A new validated SamlSecurityToken object that will expire in TokenLifetime. // SamlSecurityToken CreateSamlToken( List claims, SecurityKeyIdentifier issuerKeyIdentifier, SecurityKeyIdentifier proofKeyIdentifier, SecurityKey proofCryptoInsideSamlToken, SecurityKey issuerSigningKey, Uri immediateTokenRecipientUri ) { SamlConditions conditions; SamlSubject subject; SamlAttributeStatement subjectStatement; List allStatements; List attributes; SamlSecurityToken token; DateTime created = DateTime.UtcNow; // // Add audience restriction // Collection audiences = new Collection (); audiences.Add( immediateTokenRecipientUri ); SamlAudienceRestrictionCondition samlAudienceRestrictionCondition = new SamlAudienceRestrictionCondition( audiences ); Collection restrictionCond = new Collection (); restrictionCond.Add( samlAudienceRestrictionCondition ); conditions = new SamlConditions( created, created.Add( TokenLifetime ), restrictionCond ); string[ ] confirmationMethods = new string[ ] { null != proofKeyIdentifier ? SamlConstants.HolderOfKey : XmlNames.Saml10.Bearer }; subject = new SamlSubject( null, null, null, confirmationMethods, null, proofKeyIdentifier ); if( null != proofCryptoInsideSamlToken ) { subject.Crypto = proofCryptoInsideSamlToken; } attributes = new List ( claims.Count ); char[ ] delimter = { '/' }; for( int i = 0; i < claims.Count; i++ ) { string[ ] segments = claims[ i ].Id.Split( delimter ); IDT.ThrowInvalidArgumentConditional( 0 == segments.Length, "claimUri" ); string attrName = segments[ segments.Length - 1 ]; // // Add specific checks for gender and date of birth claims // if( claims[ i ].Id == InfoCardConstants.Gender ) { IDT.Assert( claims[ i ].Value == "0" || claims[ i ].Value == "1" || claims[ i ].Value == "2", "Wrong value type for gender claim, only values '0' (Unspecified), '1' (Male) and '2' (Female) are allowed " ); } if( claims[ i ].Id == InfoCardConstants.DateOfBirth ) { DateTime dob = DateTime.Parse( claims[ i ].Value, CultureInfo.InvariantCulture ).ToUniversalTime(); IDT.Assert( null != dob, "Invalid value for date of birth " ); attributes.Add( new SamlAttribute( XmlNames.WSIdentity.DictionaryUri, attrName, new string[ ] { XmlConvert.ToString( dob, XmlDateTimeSerializationMode.Utc ) } ) ); } else { attributes.Add( new SamlAttribute( XmlNames.WSIdentity.DictionaryUri, attrName, new string[ ] { claims[ i ].ToString() } ) ); } } subjectStatement = new SamlAttributeStatement( subject, attributes ); allStatements = new List ( 1 ); allStatements.Add( subjectStatement ); SamlAssertion assertion = new SamlAssertion( SamlAssertionIdPrefix + Guid.NewGuid().ToString(), XmlNames.WSIdentity.SelfIssuerUri, created, conditions, null, allStatements ); if( !issuerSigningKey.IsSupportedAlgorithm( m_signatureAlgorithm ) ) { throw IDT.ThrowHelperError( new TokenCreationException( SR.GetString( SR.UnsupportedSignatureAlgorithm, m_signatureAlgorithm ) ) ); } // // Set up the signing credentials. // Use the RSA key pair from the ledger for signing the token // assertion.SigningCredentials = new SigningCredentials( issuerSigningKey, m_signatureAlgorithm, DefaultDigestAlgorithm, issuerKeyIdentifier ); token = new SamlSecurityToken( assertion ); return token; } // // Summary: // Creates a display token from the list of claims that were included in the token. // // Arguments: // claims: This list of claims to add to the display token // // Returns: // A new DisplayToken object with the specified claim values. DisplayToken CreateDisplayToken( List claims ) { List displayClaims = new List (); for( int i = 0; i < claims.Count; i++ ) { List values = new List (); values.Add( claims[ i ].Value ); DisplayClaim clm = new DisplayClaim( InfoCardConstants.ClaimDisplayTag( claims[ i ].Id.ToString() ), values, InfoCardConstants.ClaimsDescription( claims[ i ].Id.ToString() ), claims[ i ].Id.ToString() ); displayClaims.Add( clm ); } DisplayToken token = new DisplayToken( displayClaims ); return token; } // // Summary: // Gets the intersecting set of claims from the specified InfoCard // // Arguments: // card: The infocard to extract the claims from. // policy: Specifies the policy of the relying party or identity provider. // discloseOptional: Specifies whether optional claims are to be disclosed. // // Returns: // returns a new collection of InfoCardClaim that were matched from the requiredClaims. // List GetClaimSet( InfoCard card, InfoCardPolicy policy, bool discloseOptional ) { StoreConnection connection = StoreConnection.GetConnection(); try { List intersectedClaims = null; if( null != policy.RequiredClaims ) { intersectedClaims = new List ( policy.RequiredClaims.Length ); AddClaimsThatIntersect( policy.RequiredClaims, false, card.GetClaims(), policy.ImmediateTokenRecipient.GetOrganizationPPIDIdentifier(), card.Id, intersectedClaims ); } if( discloseOptional && null != policy.OptionalClaims ) { // // Check to see if only optional claims were requested. // if( null == intersectedClaims ) { intersectedClaims = new List ( policy.OptionalClaims.Length ); } AddClaimsThatIntersect( policy.OptionalClaims, true, card.GetClaims(), policy.ImmediateTokenRecipient.GetOrganizationPPIDIdentifier(), card.Id, intersectedClaims ); } return intersectedClaims; } finally { connection.Close(); } } // // Summary: // Add infocardclaims that intersect with policy to intersectedClaims // // Args: // processingOptionalClaims - Whether we are intersecting optional claims or not // claims - claims we have in the card // recipientPublicKey - public key of the recipient // cardId - card id // intersectedClaims - collection to which claims that intersect are added // // Return value: // Nil (Added claims are passed to intersectedClaims). // void AddClaimsThatIntersect( string[ ] policyClaims, bool processingOptionalClaims, InfoCardClaimCollection claims, string recipientidentifier, Uri cardId, List intersectedClaims ) { foreach( string policyClaim in policyClaims ) { string policyClaimUri = policyClaim; if( policyClaimUri == InfoCardConstants.PPIDClaimsUri ) { String ppidStr = Utility.CreatePpid( Convert.FromBase64String( recipientidentifier ), cardId ); intersectedClaims.Add( new InfoCardClaim( InfoCardConstants.PPIDClaimsUri, ppidStr ) ); } else { if( !processingOptionalClaims ) { // // Required claims must have value, asserted by UI code // IDT.ThrowInvalidArgumentConditional( !claims.ContainsKey( policyClaimUri ) || null == claims[ policyClaimUri ] || String.IsNullOrEmpty( claims[ policyClaimUri ].Value ), "policyClaimUri" ); intersectedClaims.Add( claims[ policyClaimUri ] ); } else { InfoCardClaim claim = null; // // If the policyClaimUri exists in the collection. // if( claims.ContainsKey( policyClaimUri ) ) { claim = claims[ policyClaimUri ]; } // // Optional claims only sent if there is a value // if( null != claim && //InfoCardClaim pointed to by policyClaimUri is not null !String.IsNullOrEmpty( claim.Value ) ) //The value of the InfoCardClaim //is not null or empty { intersectedClaims.Add( claim ); } else { // // do nothing. Its an optional claim we don't support. // } } } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ReferencedCategoriesDocument.cs
- TagPrefixInfo.cs
- Image.cs
- ToolboxBitmapAttribute.cs
- AutomationPatternInfo.cs
- DictionaryItemsCollection.cs
- CollectionViewGroup.cs
- QueryOutputWriterV1.cs
- StateManagedCollection.cs
- FilterException.cs
- InputMethodStateChangeEventArgs.cs
- UpdatePanelTrigger.cs
- VerticalAlignConverter.cs
- WebBrowserHelper.cs
- Policy.cs
- DecimalAverageAggregationOperator.cs
- InputLanguageCollection.cs
- UnsafeNativeMethods.cs
- WindowsTooltip.cs
- GreenMethods.cs
- XmlReaderSettings.cs
- EdmMember.cs
- XmlDictionaryReader.cs
- _ListenerAsyncResult.cs
- ProvideValueServiceProvider.cs
- ModelVisual3D.cs
- AutomationPattern.cs
- InsufficientMemoryException.cs
- ObjectTypeMapping.cs
- TrackingStringDictionary.cs
- ContentDesigner.cs
- SHA384.cs
- WebReferenceCollection.cs
- DeclaredTypeValidator.cs
- SQLInt32Storage.cs
- Int32Rect.cs
- RenamedEventArgs.cs
- TextEditorCharacters.cs
- FaultReason.cs
- EdmProperty.cs
- NGCPageContentSerializerAsync.cs
- BaseResourcesBuildProvider.cs
- SqlCachedBuffer.cs
- BitmapMetadata.cs
- CryptoStream.cs
- DataGridViewAccessibleObject.cs
- AsmxEndpointPickerExtension.cs
- SqlRewriteScalarSubqueries.cs
- DynamicDataResources.Designer.cs
- Content.cs
- FixedSOMTable.cs
- ApplicationCommands.cs
- TableItemPatternIdentifiers.cs
- SystemNetHelpers.cs
- AssociatedControlConverter.cs
- KnownTypesHelper.cs
- DtdParser.cs
- HandlerFactoryWrapper.cs
- DesignerMetadata.cs
- ComboBoxItem.cs
- IsolatedStorageFile.cs
- XmlUtil.cs
- FlowLayout.cs
- HeaderedItemsControl.cs
- TableParagraph.cs
- DataColumnChangeEvent.cs
- SynchronizedPool.cs
- DataAccessor.cs
- XmlAutoDetectWriter.cs
- ExpandCollapseProviderWrapper.cs
- GridViewActionList.cs
- _NTAuthentication.cs
- ViewValidator.cs
- DtrList.cs
- SymbolEqualComparer.cs
- MailDefinition.cs
- FixedSOMTableRow.cs
- DrawingState.cs
- CollectionViewProxy.cs
- ConvertEvent.cs
- SqlParameter.cs
- UTF8Encoding.cs
- ListMarkerLine.cs
- CodeIdentifier.cs
- DecimalConverter.cs
- Accessors.cs
- GridViewEditEventArgs.cs
- Int16KeyFrameCollection.cs
- NativeActivity.cs
- BidOverLoads.cs
- MulticastOption.cs
- ISCIIEncoding.cs
- Crc32.cs
- AffineTransform3D.cs
- LayoutTable.cs
- ListItemParagraph.cs
- RegexNode.cs
- HwndMouseInputProvider.cs
- DirectoryNotFoundException.cs
- ControlAdapter.cs