diff --git a/lib/EAPBase/include/Credentials.h b/lib/EAPBase/include/Credentials.h index ea390e0..2275abc 100644 --- a/lib/EAPBase/include/Credentials.h +++ b/lib/EAPBase/include/Credentials.h @@ -111,8 +111,6 @@ namespace eap /// credentials& operator=(_Inout_ credentials &&other); - virtual config* clone() const; - /// /// Resets credentials /// @@ -149,7 +147,7 @@ namespace eap /// \param[in] pszTargetName The name in Windows Credential Manager to store credentials as /// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...) /// - virtual void store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const; + virtual void store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const = 0; /// /// Retrieve credentials from Windows Credential Manager @@ -157,7 +155,7 @@ namespace eap /// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from /// \param[in] level Credential level (0=outer, 1=inner, 2=inner-inner...) /// - virtual void retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level); + virtual void retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) = 0; /// /// Returns target name for Windows Credential Manager credential name @@ -189,7 +187,7 @@ namespace eap /// /// Return target suffix for Windows Credential Manager credential name /// - virtual LPCTSTR target_suffix() const; + virtual LPCTSTR target_suffix() const = 0; /// @} @@ -226,13 +224,105 @@ namespace eap _In_ HANDLE hTokenImpersonateUser, _In_opt_ const credentials *cred_cached, _In_ const config_method &cfg, - _In_opt_z_ LPCTSTR pszTargetName); + _In_opt_z_ LPCTSTR pszTargetName) = 0; public: std::wstring m_identity; ///< Identity (username\@domain, certificate name etc.) }; + /// + /// Identity-only based method credentials + /// + class credentials_identity : public credentials + { + public: + /// + /// Constructs credentials + /// + /// \param[in] mod EAP module to use for global services + /// + credentials_identity(_In_ module &mod); + + /// + /// Copies credentials + /// + /// \param[in] other Credentials to copy from + /// + credentials_identity(_In_ const credentials_identity &other); + + /// + /// Moves credentials + /// + /// \param[in] other Credentials to move from + /// + credentials_identity(_Inout_ credentials_identity &&other); + + /// + /// Copies credentials + /// + /// \param[in] other Credentials to copy from + /// + /// \returns Reference to this object + /// + credentials_identity& operator=(_In_ const credentials_identity &other); + + /// + /// Moves credentials + /// + /// \param[in] other Credentials to move from + /// + /// \returns Reference to this object + /// + credentials_identity& operator=(_Inout_ credentials_identity &&other); + + virtual config* clone() const; + + /// \name XML management + /// @{ + virtual void save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot) const; + virtual void load(_In_ IXMLDOMNode *pConfigRoot); + /// @} + + /// \name Storage + /// @{ + virtual void store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const; + virtual void retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level); + + /// + /// @copydoc eap::credentials::target_suffix() + /// \returns This implementation always returns `_T("pass")` + /// + virtual LPCTSTR target_suffix() const; + /// @} + + /// + /// Combine credentials in the following order: + /// + /// 1. Cached credentials + /// 2. Configured credentials (if \p cfg is derived from `config_method_with_cred`) + /// 3. Stored credentials + /// + /// \param[in] dwFlags A combination of [EAP flags](https://msdn.microsoft.com/en-us/library/windows/desktop/bb891975.aspx) that describe the EAP authentication session behavior + /// \param[in] hTokenImpersonateUser Impersonation token for a logged-on user to collect user-related information + /// \param[in] cred_cached Cached credentials (optional, can be \c NULL) + /// \param[in] cfg Method configuration (when derived from `config_method_with_cred`, metod attempt to load credentials from \p cfg) + /// \param[in] pszTargetName The name in Windows Credential Manager to retrieve credentials from (optional, can be \c NULL) + /// + /// \returns + /// - \c source_cache Credentials were obtained from EapHost cache + /// - \c source_config Credentials were set by method configuration + /// - \c source_storage Credentials were loaded from Windows Credential Manager + /// + virtual source_t combine( + _In_ DWORD dwFlags, + _In_ HANDLE hTokenImpersonateUser, + _In_opt_ const credentials *cred_cached, + _In_ const config_method &cfg, + _In_opt_z_ LPCTSTR pszTargetName); + }; + + /// /// Password based method credentials /// diff --git a/lib/EAPBase/src/Credentials.cpp b/lib/EAPBase/src/Credentials.cpp index eceb88c..33942a3 100644 --- a/lib/EAPBase/src/Credentials.cpp +++ b/lib/EAPBase/src/Credentials.cpp @@ -82,12 +82,6 @@ eap::credentials& eap::credentials::operator=(_Inout_ credentials &&other) } -eap::config* eap::credentials::clone() const -{ - return new credentials(*this); -} - - void eap::credentials::clear() { m_identity.clear(); @@ -154,14 +148,109 @@ void eap::credentials::operator>>(_Inout_ cursor_in &cursor) } -void eap::credentials::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const +wstring eap::credentials::get_identity() const +{ + return m_identity; +} + + +tstring eap::credentials::get_name() const +{ + tstring identity(std::move(get_identity())); + return + !identity.empty() ? identity : + empty() ? _T("") : _T(""); +} + + +////////////////////////////////////////////////////////////////////// +// eap::credentials_identity +////////////////////////////////////////////////////////////////////// + +eap::credentials_identity::credentials_identity(_In_ module &mod) : credentials(mod) +{ +} + + +eap::credentials_identity::credentials_identity(_In_ const credentials_identity &other) : credentials(other) +{ +} + + +eap::credentials_identity::credentials_identity(_Inout_ credentials_identity &&other) : credentials(std::move(other)) +{ +} + + +eap::credentials_identity& eap::credentials_identity::operator=(_In_ const credentials_identity &other) +{ + if (this != &other) + (credentials&)*this = other; + + return *this; +} + + +eap::credentials_identity& eap::credentials_identity::operator=(_Inout_ credentials_identity &&other) +{ + if (this != &other) + (credentials&)*this = std::move(other); + + return *this; +} + + +eap::config* eap::credentials_identity::clone() const +{ + return new credentials_identity(*this); +} + + +void eap::credentials_identity::save(_In_ IXMLDOMDocument *pDoc, _In_ IXMLDOMNode *pConfigRoot) const +{ + assert(pDoc); + assert(pConfigRoot); + + // We could have used credentials::save() to save identity, + // but that method tolerates absence of element, + // whereas for this class the absence of is fatal. + config::save(pDoc, pConfigRoot); + + HRESULT hr; + + // + if (FAILED(hr = eapxml::put_element_value(pDoc, pConfigRoot, bstr(L"UserName"), namespace_eapmetadata, bstr(m_identity)))) + throw com_runtime_error(hr, __FUNCTION__ " Error creating element."); +} + + +void eap::credentials_identity::load(_In_ IXMLDOMNode *pConfigRoot) +{ + assert(pConfigRoot); + HRESULT hr; + + // We could have used credentials::load() to load identity, + // but that method tolerates absence of element, + // whereas for this class the absence of is fatal. + config::load(pConfigRoot); + + wstring xpath(eapxml::get_xpath(pConfigRoot)); + + if (FAILED(hr = eapxml::get_element_value(pConfigRoot, bstr(L"eap-metadata:UserName"), m_identity))) + throw com_runtime_error(hr, __FUNCTION__ " Error reading element."); + + m_module.log_config((xpath + L"/UserName").c_str(), m_identity.c_str()); +} + + +void eap::credentials_identity::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) const { assert(pszTargetName); tstring target(target_name(pszTargetName, level)); // Write credentials. - assert(m_identity.length() < CRED_MAX_USERNAME_LENGTH ); + assert(m_identity.length() < CRED_MAX_USERNAME_LENGTH); CREDENTIAL cred = { 0, // Flags CRED_TYPE_GENERIC, // Type @@ -181,7 +270,7 @@ void eap::credentials::store(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int lev } -void eap::credentials::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) +void eap::credentials_identity::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int level) { assert(pszTargetName); @@ -200,28 +289,13 @@ void eap::credentials::retrieve(_In_z_ LPCTSTR pszTargetName, _In_ unsigned int } -LPCTSTR eap::credentials::target_suffix() const +LPCTSTR eap::credentials_identity::target_suffix() const { return _T("id"); } -wstring eap::credentials::get_identity() const -{ - return m_identity; -} - - -tstring eap::credentials::get_name() const -{ - tstring identity(std::move(get_identity())); - return - !identity.empty() ? identity : - empty() ? _T("") : _T(""); -} - - -eap::credentials::source_t eap::credentials::combine( +eap::credentials::source_t eap::credentials_identity::combine( _In_ DWORD dwFlags, _In_ HANDLE hTokenImpersonateUser, _In_opt_ const credentials *cred_cached, @@ -232,16 +306,16 @@ eap::credentials::source_t eap::credentials::combine( if (cred_cached) { // Using EAP service cached credentials. - *this = *cred_cached; - m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_CACHED2, event_data((unsigned int)cfg.get_method_id()), event_data(credentials::get_name()), event_data(pszTargetName), event_data::blank); + *this = *dynamic_cast(cred_cached); + m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_CACHED2, event_data((unsigned int)cfg.get_method_id()), event_data(credentials_identity::get_name()), event_data(pszTargetName), event_data::blank); return source_cache; } auto cfg_with_cred = dynamic_cast(&cfg); if (cfg_with_cred && cfg_with_cred->m_use_cred) { // Using configured credentials. - *this = *cfg_with_cred->m_cred.get(); - m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_CONFIG2, event_data((unsigned int)cfg.get_method_id()), event_data(credentials::get_name()), event_data(pszTargetName), event_data::blank); + *this = *dynamic_cast(cfg_with_cred->m_cred.get()); + m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_CONFIG2, event_data((unsigned int)cfg.get_method_id()), event_data(credentials_identity::get_name()), event_data(pszTargetName), event_data::blank); return source_config; } @@ -250,12 +324,12 @@ eap::credentials::source_t eap::credentials::combine( user_impersonator impersonating(hTokenImpersonateUser); try { - credentials cred_loaded(m_module); + credentials_identity cred_loaded(m_module); cred_loaded.retrieve(pszTargetName, cfg.m_level); // Using stored credentials. *this = std::move(cred_loaded); - m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_STORED2, event_data((unsigned int)cfg.get_method_id()), event_data(credentials::get_name()), event_data(pszTargetName), event_data::blank); + m_module.log_event(&EAPMETHOD_TRACE_EVT_CRED_STORED2, event_data((unsigned int)cfg.get_method_id()), event_data(credentials_identity::get_name()), event_data(pszTargetName), event_data::blank); return source_storage; } catch (...) { // Not actually an error.