alter Code:
Code: Select all
public __gc __abstract class Credential : public IDisposable
{
public:
// types
__value enum Package {Negotiate, Kerberos, NTLM};
__value enum CredentialType {Client, Server};
// constructor/destructor
Credential(Package package, CredentialType credentialType)
{
// we're not disposed yet
this->disposed = false;
// create a new credential handle
// note: we're allocating the CredHandle on the C++ heap. This needs to be
// explicitly deleted upon Disposal
this->credentialHandle = __nogc new CredHandle;
this->credentialHandle->dwLower = 0; this->credentialHandle->dwUpper = 0;
// capture the package
this->securityPackage = package;
// determine package name for the call the AcquireCredentialsHandle
TCHAR *pszPackageName = NULL;
switch (package)
{
case Package::Negotiate:
pszPackageName = szNegotiatePackageName;
break;
case Package::Kerberos:
pszPackageName = szKerberosPackageName;
break;
case Package::NTLM:
pszPackageName = szNTLMPackageName;
break;
}
// determine credential use
ULONG fCredentialUse = 0;
switch (credentialType)
{
case CredentialType::Client:
fCredentialUse = SECPKG_CRED_OUTBOUND;
break;
case CredentialType::Server:
fCredentialUse = SECPKG_CRED_INBOUND;
break;
}
// acquire credentials handle
TimeStamp tsExpiry = { 0, 0 };
// suppressing Code Analysis warning, as we will not disturb this code going forward
#pragma warning(suppress: 6387)
SECURITY_STATUS sResult = AcquireCredentialsHandle(
NULL, // [in] name of principal. NULL = principal of current security context
pszPackageName, // [in] name of package
fCredentialUse, // [in] flags indicating use.
NULL, // [in] pointer to logon identifier. NULL = we're not specifying the id of another logon session
NULL, // [in] package-specific data. NULL = default credentials for security package
NULL, // [in] pointer to GetKey function. NULL = we're not using a callback to retrieve the credentials
NULL, // [in] value to pass to GetKey
this->credentialHandle, // [out] credential handle (this must be already allocated)
&tsExpiry // [out] lifetime of the returned credentials
);
// check for errors
if (sResult != SEC_E_OK)
{
SSPIException *ex = new SSPIException(S"AcquireCredentialsHandle failed", sResult);
throw ex;
}
}
~Credential()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
// Implement IDisposable*
// Do not make this method virtual.
// A derived class should not be able to call this method.
void Dispose()
{
Dispose(true);
// Take ourselves off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC::SuppressFinalize(this);
}
protected:
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this->disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources
// (there are no managed resources here)
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
// clean up
SECURITY_STATUS sResult = FreeCredentialsHandle(
this->credentialHandle // [in] handle to free
);
// delete the memory allocated for the handle
delete this->credentialHandle;
this->credentialHandle = NULL;
// check for errors
if (sResult != SEC_E_OK)
{
// VA: In .NET 2.0 the unhandled exception causes the application to terminate.
//SSPIException *ex = new SSPIException(S"FreeCredentialsHandle failed", sResult);
//throw ex;
}
}
this->disposed = true;
}
public:
// properties
__property Package get_SecurityPackage()
{
if(this->disposed)
throw new ObjectDisposedException(this->GetType()->Name);
return this->securityPackage;
};
__property IntPtr get_CredentialHandle()
{
if(this->disposed)
throw new ObjectDisposedException(this->GetType()->Name);
return IntPtr(this->credentialHandle);
};
__property String *get_Name()
{
if(this->disposed)
throw new ObjectDisposedException(this->GetType()->Name);
String *name = NULL;
// get the name associated with this credential
SecPkgCredentials_Names secPkgCredentials_Names = { 0 };
try
{
SECURITY_STATUS sResult = QueryCredentialsAttributes(this->credentialHandle, SECPKG_CRED_ATTR_NAMES, &secPkgCredentials_Names);
// check for errors
if (sResult != SEC_E_OK)
{
SSPIException *ex = new SSPIException(S"QueryCredentialsAttributes failed", sResult);
throw ex;
}
// copy the name for the caller
name = secPkgCredentials_Names.sUserName;
}
__finally
{
// free the buffer
if (secPkgCredentials_Names.sUserName != NULL)
{
FreeContextBuffer(secPkgCredentials_Names.sUserName);
secPkgCredentials_Names.sUserName = NULL;
}
}
// return the name to the caller
return name;
};
private:
// member variables
CredHandle __nogc* credentialHandle;
Package securityPackage;
bool disposed;
};
// SafeHandle for managing the CredHandle
ref class SafeCredHandle sealed : public SafeHandle
{
public:
SafeCredHandle()
: SafeHandle(IntPtr::Zero, true)
{
//handle = Marshal::AllocHGlobal(sizeof(::CredHandle));
//ZeroMemory((void*)handle, sizeof(::CredHandle));
}
SafeCredHandle(CredHandle* handle)
: SafeHandle(IntPtr::Zero, true)
{
if (handle != nullptr)
{
this->SetHandle(IntPtr(handle));
}
}
property ::CredHandle* NativeHandle
{
::CredHandle* get()
{
return reinterpret_cast(handle.ToPointer());
}
}
[SecurityCritical]
virtual property bool IsInvalid
{
bool get() override
{
return handle == IntPtr::Zero;
}
}
protected:
[SecurityCritical]
virtual bool ReleaseHandle() override
{
if (handle != IntPtr::Zero)
{
SECURITY_STATUS status = FreeCredentialsHandle(reinterpret_cast(handle.ToPointer()));
handle = IntPtr::Zero;
return (status == SEC_E_OK);
}
return true;
}
};
public ref class Credential
{
public:
// types
enum class Package { Negotiate, Kerberos, NTLM };
enum class CredentialType { Client, Server };
// constructor/destructor
Credential(Package package, CredentialType credentialType)
{
// we're not disposed yet
this->disposed = false;
// capture the package
this->securityPackage = package;
// determine package name for the call the AcquireCredentialsHandle
TCHAR* pszPackageName = nullptr;
switch (package)
{
case Package::Negotiate:
pszPackageName = szNegotiatePackageName;
break;
case Package::Kerberos:
pszPackageName = szKerberosPackageName;
break;
case Package::NTLM:
pszPackageName = szNTLMPackageName;
break;
}
// determine credential use
ULONG fCredentialUse = 0;
switch (credentialType)
{
case CredentialType::Client:
fCredentialUse = SECPKG_CRED_OUTBOUND;
break;
case CredentialType::Server:
fCredentialUse = SECPKG_CRED_INBOUND;
break;
}
CredHandle* rawHandle = new CredHandle();
// acquire credentials handle
TimeStamp tsExpiry = { 0, 0 };
// suppressing Code Analysis warning, as we will not disturb this code going forward
#pragma warning(suppress: 6387)
SECURITY_STATUS sResult = AcquireCredentialsHandle(
nullptr, // [in] name of principal. NULL = principal of current security context
pszPackageName, // [in] name of package
fCredentialUse, // [in] flags indicating use.
nullptr, // [in] pointer to logon identifier. NULL = we're not specifying the id of another logon session
nullptr, // [in] package-specific data. NULL = default credentials for security package
nullptr, // [in] pointer to GetKey function. NULL = we're not using a callback to retrieve the credentials
nullptr, // [in] value to pass to GetKey
rawHandle, // [out] credential handle (this must be already allocated)
&tsExpiry // [out] lifetime of the returned credentials
);
// check for errors
if (sResult != SEC_E_OK)
{
SSPIException^ ex = gcnew SSPIException("AcquireCredentialsHandle failed", sResult);
throw ex;
}
this->credentialHandle = gcnew SafeCredHandle(rawHandle);
}
//Destructor to free managed code
~Credential()
{
this->!Credential();
}
//Finalizer to free unmanaged code
!Credential()
{
if (!disposed)
{
if (credentialHandle != nullptr)
{
credentialHandle->Close();
credentialHandle = nullptr;
}
this->disposed = true;
}
}
public:
// properties
property Credential::Package SecurityPackage
{
Credential::Package get()
{
if (disposed || credentialHandle == nullptr || credentialHandle->IsInvalid)
throw gcnew ObjectDisposedException(this->GetType()->Name);
return securityPackage;
}
};
property IntPtr CredentialHandle
{
IntPtr get()
{
if (disposed || credentialHandle == nullptr || credentialHandle->IsInvalid)
throw gcnew ObjectDisposedException(this->GetType()->Name);
return IntPtr(credentialHandle->NativeHandle);
}
};
property String^ Name
{
String^ get()
{
if (disposed || credentialHandle == nullptr || credentialHandle->IsInvalid)
throw gcnew ObjectDisposedException(this->GetType()->Name);
String^ name = nullptr;
// get the name associated with this credential
SecPkgCredentials_Names secPkgCredentials_Names = { 0 };
try
{
SECURITY_STATUS sResult = QueryCredentialsAttributes(credentialHandle->NativeHandle, SECPKG_CRED_ATTR_NAMES, &secPkgCredentials_Names);
// check for errors
if (sResult != SEC_E_OK)
{
SSPIException^ ex = gcnew SSPIException("QueryCredentialsAttributes failed", sResult);
throw ex;
}
// copy the name for the caller
name = gcnew String(secPkgCredentials_Names.sUserName);
}
__finally
{
// free the buffer
if (secPkgCredentials_Names.sUserName != nullptr)
{
FreeContextBuffer(secPkgCredentials_Names.sUserName);
secPkgCredentials_Names.sUserName = nullptr;
}
}
// return the name to the caller
return name;
}
};
private:
// member variables
SafeCredHandle^ credentialHandle;
Credential::Package securityPackage;
bool disposed;
};
< /code>
Warnungen: < /strong> < /p>
-Warning: Ca2004: Microsoft. Nachsichtlichkeit: 'safecredHandle. Ressource). 'SecurityCriticalAttribute'. Ressource). /> < /blockquote>
-Warning: Ca2004: Microsoft.Rficability: 'Anmeldeinformationen.Credential (Anmeldeinformationen.Package, Anmeldeinformationen.CredentialType)' enthält einen oder mehrere Aufrufe, die auf GC.Keepalive (Objekte zu veranlassen). /> < /blockquote>
-Warning: Ca2004: Microsoft.sicherheit: 'Anmeldeinformationen.CredentialHandle.get () enthält einen oder mehrere Anrufe an GC.Keepalive (Objekt), die entfernt werden sollten (nach dem Konvertieren in die unmanagierte Ressource). />
[Ort nicht in PDB gespeichert]: WARNUNG: CA2004: Microsoft. /> -Warning: CA2004: Microsoft.Relability: 'Anmeldeinformationen.name.get ()' enthält einen oder mehrere Aufrufe an GC.Keepalive (Objekt), die entfernt werden sollten (nach Konvertieren in SaferHandle, um die nicht verwaltete Ressourcen zu decapsulating). Microsoft.Relability: 'Anmeldeinformationen. Erscheinen:
Trotz des Umschaltens zu SafeHandle bekomme ich immer noch die gleichen CA2004 -Warnungen. Die Warnungen deuten darauf hin, dass GC.Keepalive -Anrufe nach dem Konvertieren in SafeHandle entfernt werden sollten, aber ich kann sie nicht loswerden. Der Destruktor von ~ Anmeldeinformationen () wird niemals aufgerufen, auch wenn ich die Klasse in einem verwendeten Block oder manuell aufgerufene Dispose () verwende. Dies führt dazu, dass nicht verwaltete Ressourcen nicht ordnungsgemäß gereinigt werden. Aktualisieren? Wie kann ich es richtig in meine Klasse integrieren? Jeder Beispielcode oder eine Anleitung wäre sehr geschätzt.