1
/****************************************************************************
3
| Copyright (c) 2007 Novell, Inc.
6
| This program is free software; you can redistribute it and/or
7
| modify it under the terms of version 2 of the GNU General Public License as
8
| published by the Free Software Foundation.
10
| This program is distributed in the hope that it will be useful,
11
| but WITHOUT ANY WARRANTY; without even the implied warranty of
12
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
| GNU General Public License for more details.
15
| You should have received a copy of the GNU General Public License
16
| along with this program; if not, contact Novell, Inc.
18
| To contact Novell about this file by physical or electronic mail,
19
| you may find current contact information at www.novell.com
21
| Author: Mike Lasky <mlasky@novell.com>
22
|***************************************************************************/
25
using System.Collections;
27
using System.Security.Cryptography;
32
using Persist = Simias.Storage.Provider;
34
namespace Simias.Storage
37
/// Class that represents a user identity in the Collection Store.
39
public class Identity : Node
43
/// Used to log messages.
45
static private readonly ISimiasLog log = SimiasLogManager.GetLogger( typeof( Identity ) );
48
/// This is used to keep from generating a new key set everytime a new RSACryptoSecurityProvider
49
/// object is instantiated. This is passed as a parameter to the constructor and will initially
50
/// use the dummy key set until the real key set is imported.
52
static private CspParameters DummyParameters;
55
/// Xml tags used to store the domain mapping information.
57
static private readonly string MappingTag = "Mapping";
58
static private readonly string DomainTag = "Domain";
59
static private readonly string UserTag = "User";
60
static private readonly string CredentialTag = "Credential";
61
static private readonly string TypeTag = "Type";
62
static private readonly string PassPhraseTag = "PassPhrase";
63
static private readonly string PassPhraseTypeTag = "PassPhraseType";
64
static private readonly string RememberPassPhraseTag = "RememberPassPhrase";
67
/// Handle to the store.
69
private Store store = null;
74
/// Gets the store handle.
76
private Store StoreReference
82
store = Store.GetStore();
90
/// Gets the public/private key values for the local identity.
92
public RSACryptoServiceProvider Credential
96
RSACryptoServiceProvider credential = null;
98
// Lookup the credential property on the identity.
99
XmlDocument mapDoc = GetDocumentByDomain( StoreReference.LocalDomain );
100
if ( mapDoc != null )
102
credential = DummyCsp;
103
credential.FromXmlString( mapDoc.DocumentElement.GetAttribute( CredentialTag ) );
111
/// Returns the number of subscribed domains.
113
internal int DomainCount
117
MultiValuedList mvl = properties.GetProperties( PropertyTags.Domain );
123
/// Gets the public key for the Identity object.
125
public RSACryptoServiceProvider PublicKey
129
// Export the public key from the credential set.
130
RSACryptoServiceProvider pk = null;
131
RSACryptoServiceProvider credential = Credential;
132
if ( credential != null )
135
pk.ImportParameters( credential.ExportParameters( false ) );
143
/// Gets the CSP for the dummy key container.
145
static internal RSACryptoServiceProvider DummyCsp
149
RSACryptoServiceProvider csp = null;
151
lock( DummyParameters )
155
csp = new RSACryptoServiceProvider( DummyParameters );
157
catch ( CryptographicException e )
159
log.Debug( e, "Corrupt cryptographic key container." );
161
IntPtr phProv = IntPtr.Zero;
162
if ( CryptAcquireContext(
164
DummyParameters.KeyContainerName,
165
"Microsoft Strong Cryptographic Provider",
167
0x10) ) // CRYPT_DELETEKEYSET
169
csp = new RSACryptoServiceProvider( DummyParameters );
182
[System.Runtime.InteropServices.DllImport( "advapi32.dll", SetLastError=true )]
183
static extern bool CryptAcquireContext( ref IntPtr phProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags );
189
/// Static constructor for the object.
193
// Set up the dummy key store so that it will contain a dummy key set.
194
DummyParameters = new CspParameters();
195
DummyParameters.KeyContainerName = "DummyKeyStore";
196
RSACryptoServiceProvider csp = DummyCsp;
200
/// Constructor for creating a new Identity object.
202
/// <param name="store">A handle to the store.</param>
203
/// <param name="userName">User name of the identity.</param>
204
/// <param name="userGuid">Unique identifier for the user.</param>
205
internal Identity( Store store, string userName, string userGuid ) :
206
base ( userName, userGuid, NodeTypes.IdentityType )
212
/// Constructor that creates an Identity object from a Node object.
214
/// <param name="node">Node object to create the Identity object from.</param>
215
internal Identity( Node node ) :
218
if ( type != NodeTypes.IdentityType )
220
throw new CollectionStoreException( String.Format( "Cannot construct an object type of {0} from an object of type {1}.", NodeTypes.IdentityType, type ) );
225
/// Constructor that creates an Identity object from a ShallowNode object.
227
/// <param name="collection">Collection that the specified Node object belongs to.</param>
228
/// <param name="shallowNode">ShallowNode object to create the Identity object from.</param>
229
internal Identity( Collection collection, ShallowNode shallowNode ) :
230
base( collection, shallowNode )
232
if ( type != NodeTypes.IdentityType )
234
throw new CollectionStoreException( String.Format( "Cannot construct an object type of {0} from an object of type {1}.", NodeTypes.IdentityType, type ) );
239
/// Constructor that creates an Identity object from an Xml document object.
241
/// <param name="document">Xml document object to create the Identity object from.</param>
242
internal Identity( XmlDocument document ) :
245
if ( type != NodeTypes.IdentityType )
247
throw new CollectionStoreException( String.Format( "Cannot construct an object type of {0} from an object of type {1}.", NodeTypes.IdentityType, type ) );
252
#region Private Methods
254
/// Decrypts the credential.
256
/// <param name="encryptedCredential">A string object that contain the encrypted credential.</param>
257
/// <returns>A string object containing the clear credential.</returns>
258
private string DecryptCredential( string encryptedCredential )
260
// Decrypt the byte array and convert it back into a string.
261
byte[] buffer = Credential.Decrypt( Convert.FromBase64String( encryptedCredential ), false );
262
return new UTF8Encoding().GetString( buffer );
266
/// Encrypts the credential.
268
/// <param name="credential">Credential to encrypt.</param>
269
/// <returns>A string object containing the encrypted credential.</returns>
270
private string EncryptCredential( string credential )
272
// Convert the string to a byte array.
273
UTF8Encoding encoding = new UTF8Encoding();
274
int byteCount = encoding.GetByteCount( credential );
275
byte[] buffer = new byte[ byteCount ];
276
encoding.GetBytes( credential, 0, credential.Length, buffer, 0 );
278
// Encrypt the byte array and turn it into a string.
279
return Convert.ToBase64String( Credential.Encrypt( buffer, false ) );
283
/// Gets the XML document that contains the specified Domain property.
285
/// <param name="domainID">Well known identity for the specified domain.</param>
286
/// <returns>An XmlDocument object containing the found domain property.</returns>
287
private XmlDocument GetDocumentByDomain( string domainID )
289
XmlDocument document = null;
291
MultiValuedList mvl = properties.GetProperties( PropertyTags.Domain );
292
foreach ( Property p in mvl )
294
XmlDocument mapDoc = p.Value as XmlDocument;
295
if ( mapDoc.DocumentElement.GetAttribute( DomainTag ) == domainID )
306
/// Gets the XML document that contains the specified Domain property.
308
/// <param name="userID">User ID to use to discover domain property.</param>
309
/// <returns>An XmlDocument object containing the found domain property.</returns>
310
private XmlDocument GetDocumentByUserID( string userID )
312
XmlDocument document = null;
314
MultiValuedList mvl = properties.GetProperties( PropertyTags.Domain );
315
foreach ( Property p in mvl )
317
XmlDocument mapDoc = p.Value as XmlDocument;
318
if ( mapDoc.DocumentElement.GetAttribute( UserTag ) == userID )
329
/// Gets the specified Domain property.
331
/// <param name="domainID">Well known identity for the specified domain.</param>
332
/// <returns>A Property object containing the found domain property.</returns>
333
private Property GetPropertyByDomain( string domainID )
335
Property property = null;
337
MultiValuedList mvl = properties.GetProperties( PropertyTags.Domain );
338
foreach ( Property p in mvl )
340
XmlDocument mapDoc = p.Value as XmlDocument;
341
if ( mapDoc.DocumentElement.GetAttribute( DomainTag ) == domainID )
352
/// Gets the specified Domain property.
354
/// <param name="userID">User ID to use to discover domain property.</param>
355
/// <returns>A Property object containing the found domain property.</returns>
356
private Property GetPropertyByUserID( string userID )
358
Property property = null;
360
MultiValuedList mvl = properties.GetProperties( PropertyTags.Domain );
361
foreach ( Property p in mvl )
363
XmlDocument mapDoc = p.Value as XmlDocument;
364
if ( mapDoc.DocumentElement.GetAttribute( UserTag ) == userID )
375
#region Internal Methods
377
/// Adds a domain identity property to the Identity object.
379
/// <param name="userID">Identity that this user is known as in the specified domain.</param>
380
/// <param name="domainID">Well known identity for the specified domain.</param>
381
/// <returns>The modified identity object.</returns>
382
internal Identity AddDomainIdentity( string userID, string domainID )
384
return AddDomainIdentity( userID, domainID, null, CredentialType.None );
388
/// Adds a domain identity property to the Identity object.
390
/// <param name="userID">Identity that this user is known as in the specified domain.</param>
391
/// <param name="domainID">Well known identity for the specified domain.</param>
392
/// <param name="credentials">Credentials for this domain. This may be null.</param>
393
/// <param name="type">The type of credentials stored.</param>
394
/// <returns>The modified identity object.</returns>
395
internal Identity AddDomainIdentity( string userID, string domainID, string credentials, CredentialType type )
397
XmlDocument mapDoc = null;
399
// Check to see if the domain already exists.
400
Property p = GetPropertyByDomain( domainID );
403
mapDoc = p.Value as XmlDocument;
407
mapDoc = new XmlDocument();
408
XmlElement root = mapDoc.CreateElement( MappingTag );
409
mapDoc.AppendChild( root );
410
mapDoc.DocumentElement.SetAttribute( DomainTag, domainID );
412
p = new Property( PropertyTags.Domain, mapDoc );
413
properties.AddNodeProperty( p );
416
mapDoc.DocumentElement.SetAttribute( UserTag, userID );
417
mapDoc.DocumentElement.SetAttribute( TypeTag, type.ToString() );
419
if ( ( credentials != null ) && ( type != CredentialType.None ) )
421
if ( type == CredentialType.Basic )
423
mapDoc.DocumentElement.SetAttribute( CredentialTag, EncryptCredential( credentials ) );
427
mapDoc.DocumentElement.SetAttribute( CredentialTag, credentials );
431
p.SetPropertyValue( mapDoc );
436
/// Removes the specified domain mapping from the identity object.
438
/// <param name="domainID">Well known identity for the specified domain.</param>
439
/// <returns>The modified identity object.</returns>
440
internal Identity DeleteDomainIdentity( string domainID )
442
// Do not allow the local domain to be deleted.
443
if ( domainID == StoreReference.LocalDomain )
445
throw new CollectionStoreException( "Cannot remove the local domain." );
448
// Find the property to be deleted.
449
Property p = GetPropertyByDomain( domainID );
459
/// Gets the domain associated with the specified user ID.
461
/// <param name="userID">User ID to find the associated domain for.</param>
462
/// <returns>Domain name associated with the specified user ID if it exists. Otherwise null is returned.</returns>
463
internal string GetDomainFromUserID( string userID )
465
string domainID = null;
467
// Find the property associated with the user ID.
468
XmlDocument document = GetDocumentByUserID( userID );
469
if ( document != null )
471
domainID = document.DocumentElement.GetAttribute( DomainTag );
474
return ( ( domainID != null ) && ( domainID != String.Empty ) ) ? domainID : null;
478
/// Gets the user ID associated with the specified domain ID.
480
/// <param name="domainID">Well known identity for the specified domain.</param>
481
/// <returns>User ID associated with the specified domain ID if it exists. Otherwise null is returned.</returns>
482
internal string GetUserIDFromDomain( string domainID )
484
string userID = null;
486
// Find the property associated with the user ID.
487
XmlDocument document = GetDocumentByDomain( domainID );
488
if ( document != null )
490
userID = document.DocumentElement.GetAttribute( UserTag );
493
return ( ( userID != null ) && ( userID != String.Empty ) ) ? userID : null;
497
/// Gets the user identifier and credentials for the specified domain.
499
/// <param name="domainID">The identifier for the domain.</param>
500
/// <param name="userID">Gets the userID of the user associated with the specified domain.</param>
501
/// <param name="credentials">Gets the credentials for the user.</param>
502
/// <returns>CredentialType enumerated object.</returns>
503
internal CredentialType GetDomainCredentials( string domainID, out string userID, out string credentials )
505
// Find the property associated with the domain.
506
XmlDocument document = GetDocumentByDomain( domainID );
507
if ( document == null )
509
throw new CollectionStoreException( "The specified domain does not exist." );
512
// Return the User ID.
513
userID = document.DocumentElement.GetAttribute( UserTag );
515
// Get the credential type.
516
string credTypeString = document.DocumentElement.GetAttribute( TypeTag );
517
CredentialType credType = ( CredentialType )Enum.Parse( typeof( CredentialType ), credTypeString, true );
519
// Return the credentials.
520
credentials = document.DocumentElement.GetAttribute( CredentialTag );
521
if ( credentials != String.Empty )
523
if ( credType == CredentialType.Basic )
525
credentials = DecryptCredential( credentials );
537
/// Gets the user identifier and pass-phrase for the specified domain.
539
/// <param name="domainID">The identifier for the domain.</param>
540
/// <param name="userID">Gets the userID of the user associated with the specified domain.</param>
541
/// <param name="credentials">Gets the credentials for the user.</param>
542
/// <returns>CredentialType enumerated object.</returns>
543
internal bool GetRememberOption( string domainID)
546
// Find the property associated with the domain.
547
XmlDocument document = GetDocumentByDomain( domainID );
548
if ( document == null )
550
throw new CollectionStoreException( "The specified domain does not exist." );
553
// Return the remember
554
remember = document.DocumentElement.GetAttribute( RememberPassPhraseTag );
555
if (remember == "true")
563
/// Gets the user identifier and pass-phrase for the specified domain.
565
/// <param name="domainID">The identifier for the domain.</param>
566
/// <param name="userID">Gets the userID of the user associated with the specified domain.</param>
567
/// <param name="credentials">Gets the credentials for the user.</param>
568
/// <returns>CredentialType enumerated object.</returns>
569
internal string GetPassPhrase( string domainID)
571
// Find the property associated with the domain.
572
XmlDocument document = GetDocumentByDomain( domainID );
573
if ( document == null )
575
throw new CollectionStoreException( "The specified domain does not exist." );
578
// Get the credential type.
579
string credTypeString = document.DocumentElement.GetAttribute( PassPhraseTypeTag );
580
if( credTypeString == null || credTypeString == String.Empty)
584
CredentialType credType = ( CredentialType )Enum.Parse( typeof( CredentialType ), credTypeString, true );
586
// Return the credentials.
587
string passPhrase = document.DocumentElement.GetAttribute( PassPhraseTag );
588
if ( passPhrase != null && passPhrase != String.Empty )
590
if ( credType == CredentialType.Basic )
592
passPhrase = DecryptCredential( passPhrase );
603
/// Sets the credentials for the specified domain.
605
/// <param name="domainID">The domain to set the password for.</param>
606
/// <param name="credentials">The domain credentials.</param>
607
/// <param name="type">Type of credentials.</param>
608
/// <returns>The modified identity object.</returns>
609
internal Identity SetDomainCredentials( string domainID, string credentials, CredentialType type )
611
Property p = GetPropertyByDomain( domainID );
614
throw new CollectionStoreException( "There is no mapping for this domain." );
617
// Set the password on the mapping.
618
XmlDocument mapDoc = p.Value as XmlDocument;
619
if ( type == CredentialType.None )
621
if ( domainID == StoreReference.LocalDomain )
623
throw new CollectionStoreException( "Cannot remove the local domain credentials." );
626
mapDoc.DocumentElement.RemoveAttribute( CredentialTag );
630
if ( type == CredentialType.Basic )
632
mapDoc.DocumentElement.SetAttribute( CredentialTag, EncryptCredential( credentials ) );
636
mapDoc.DocumentElement.SetAttribute( CredentialTag, credentials );
640
mapDoc.DocumentElement.SetAttribute( TypeTag, type.ToString() );
641
p.SetPropertyValue( mapDoc );
646
/// Stores the passphrase for the specified domain.
648
/// <param name="domainID">The domain to store the passphrase for.</param>
649
/// <param name="passPhrase">The domain passphrase.</param>
650
/// <param name="type">Type of credentials.</param>
651
/// <returns>The modified identity object.</returns>
652
internal Identity StorePassPhrase( string domainID, string passPhrase, CredentialType type, bool rememberPassPhrase)
654
Property p = GetPropertyByDomain( domainID );
657
throw new CollectionStoreException( "There is no mapping for this domain." );
660
// Set the password on the mapping.
661
XmlDocument mapDoc = p.Value as XmlDocument;
662
if ( type == CredentialType.None )
664
mapDoc.DocumentElement.RemoveAttribute( PassPhraseTag );
665
mapDoc.DocumentElement.RemoveAttribute(RememberPassPhraseTag);
669
if ( type == CredentialType.Basic )
671
if( passPhrase != null && passPhrase != "")
672
mapDoc.DocumentElement.SetAttribute( PassPhraseTag, EncryptCredential( passPhrase ) );
676
mapDoc.DocumentElement.SetAttribute( PassPhraseTag, passPhrase );
678
if(rememberPassPhrase)
679
mapDoc.DocumentElement.SetAttribute( RememberPassPhraseTag, "true");
681
mapDoc.DocumentElement.SetAttribute( RememberPassPhraseTag, "false");
684
mapDoc.DocumentElement.SetAttribute( PassPhraseTypeTag, type.ToString() );
685
p.SetPropertyValue( mapDoc );
689
public RSACryptoServiceProvider GetDomainCredential(string domainID)
691
RSACryptoServiceProvider credential = null;
693
// Lookup the credential property on the identity.
694
XmlDocument mapDoc = GetDocumentByDomain( domainID );
695
if ( mapDoc != null )
697
credential = DummyCsp;
698
credential.FromXmlString( mapDoc.DocumentElement.GetAttribute( CredentialTag ) );