C++ Windows Credential Provider Error Screen - c++

I have developed a custom credential provider for MFA and it is working fine. I am performing my additional authentication checks in GetSerialization() method by calling REST APIs. Now, in case of successful validation through REST API, I am allowing the user to login. But for the case of validation failure, I want to show error screen, like the one default provider shows in case of incorrect username or password (having a button for 'Ok'). I have understood that this is done in ReportResult() by default credential provider in case of logon failure. Can I call ReportResult() to display my custom error message with an 'Ok' button?
Regards,
EDIT: I am doing it like this:
if (SUCCEEDED(HRESULT_FROM_NT(ntsStatus)) && SUCCEEDED(HRESULT_FROM_NT(ntsSubstatus)))
{
SHStrDupW(L"Bad password", ppwszOptionalStatusText);
*pcpsiOptionalStatusIcon = CPSI_ERROR;
}
But the screen isn't stopping. It logs in the user. I need to detect the scenario when the windows credentials are correct but the API call fails, so I need to catch that status and display error

Have to try
*pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;
In my use case wih additional
*pcpsiOptionalStatusIcon = CPSI_WARNING;
it is enough to display status message.

ReportResult(
NTSTATUS ntsStatus,
NTSTATUS ntsSubstatus,
PWSTR* ppwszOptionalStatusText,
CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
)
You can set your own custom message by populating ppwszOptionalStatusText. If needed, icon can also be set pcpsiOptionalStatusIcon to one of CPSI_ERROR,CPSI_WARNING or CPSI_SUCCESS.
For eg., after checking on ntsStatus, you could customize like this
SHStrDupW(L"Bad password", ppwszOptionalStatusText);
*pcpsiOptionalStatusIcon = CPSI_ERROR;
Edit:
Inside GetSerialization(), once the API returns failure, set the CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE to not finished. Like this
*pcpgsr = CPGSR_RETURN_NO_CREDENTIAL_FINISHED;
This should stop the logon to continue.
Edit 2:
As per #js.hrt comment below, to show the status screen from GetSerialization, by using *pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED; SHStrDupW(L"Bad password", ppwszOptionalStatusText); *pcpsiOptionalStatusIcon = CPSI_ERROR; in GetSerialization() without using report result.

Related

oAuth2.0 authentication in C++

I have a desktop application in which I need to make a user authentication with oAuth2.0.
I looked at the Facebook example but it doesn't really correspond to what I have to do or I don't understand it well.
In fact, I create an O2 instance:
O2* o2Auth;
o2Auth = new o2Auth(this);
o2Auth->setClientId(CLIENT_ID);
o2Auth->setClientSecret(CLIENT_SECRET);
o2Auth->setRequestUrl(REQUEST_URL);
o2Auth->setTokenUrl(TOKEN_URL);
But I don't understand how to authenticate the user with the user name and password. Which function do I have to use to do that?
In Facebook example, there is:
if (argList.contains(OPT_OAUTH_CODE)) {
// Start OAuth
fbdemo_.doOAuth(O2::GrantFlowAuthorizationCode);
} else if (argList.contains(OPT_VALIDATE_TOKEN)) {
fbdemo_.validateToken();
}
where argList is the parameters given to the application but they are not the user name and password.
In the tweeter example, there is :
oxTwitter_->setUsername(username);
oxTwitter_->setPassword(password);
but I didn't find the equivalent in O2.
I think I have to use things like GET and POST functions in the OSRequestor class, but how to link a OSRequestor instance to my O2 instance?
So what do I need to send user name and password to do the authentication with O2?

Custom Windows Authentication Package Logon Failed

I have developed custom authentication package that I would like to use for interactive logon. It creates the access token in the LsaApUserLogon function.
When I call LsaUserLogon from an application I can enumerate new user sessions, but when I used it for logon (also I have created a custom credential provider) I can see in Windows Event log that I was successfully logged in and then logged out.
When I select my specific Credential and try to logon, it enters into LsaApLogonUser API of my Authentication Package. If I check log file, LsaApLogonUser return STATUS_SUCCESS. But Windows is not logged on. After leaving LsaAPLogonUser, LSA calls LsaApLogonTerminated API and back LogonUI.
When I prepared the TokenInformation I got LookupPrivilegeValueW failed for the SeInteractiveLogonRight. I don't know if this is important for logon.
LsaApLogonUser(...){
......
// NetUserGetInfo
// AllocateLocallyUniqueId (LogonId)
err = GetTokenInformationv2(pdi?pdi->DomainControllerName:NULL,wszDomain,wszUser,&LocalTokenInformation,LogonId);
err = g_pSec->CreateLogonSession(LogonId);
if(ProfileBuffer)
{
*ProfileBuffer=NULL;
*ProfileBufferLength=0;
}
(*TokenInformationType)=LsaTokenInformationV2;
(*TokenInformation)=LocalTokenInformation;
return STATUS_SUCCESS;
}
GetTokenInformationv2(...){
....
....
// Call LsaEnumerateAccountRights
// check LookupPrivilegeValueW // It failed for "SeInteractiveLogonRight"
//
return STATUS_SUCCESS;
}
Is ProfileBuffer important for logon? I don't know why LSA cannot logon.
The documentation does not say that the profile buffer can be set to NULL and it seems that it is indeed mandatory. The OP reports that allocating and returning a profile buffer (just a single byte was enough) resolved the problem.
The error when attempting to retrieve a LUID for SeInteractiveLogonRight was not relevant; the user's logon rights do not need to be included in the TOKEN_PRIVILEGES structure, so no LUID is needed, and as documented, the LookupPrivilegeValue function only accepts privileges:
The LookupPrivilegeValue function supports only the privileges specified in the Defined Privileges section of Winnt.h.
(Note that the relevant section of winnt.h only contains definitions for SeXxxPrivilege; the definitions for SeXxxLogonRight are in ntsecapi.h.)

WSO2 Identity Server - UserInformationRecoveryService not returning needed error message on invalid password

I am trying to use the WSO2 Identity Server 5.0.0 UserInformationRecoveryService but it does not appear to properly handle invalid passwords when calling "registerUser()". I would expect the service to return some information informing the client that the password is invalid but instead I get a 500 error and the following exception:
org.wso2.carbon.identity.mgt.stub.UserInformationRecoveryServiceIdentityMgtServiceExceptionException: UserInformationRecoveryServiceIdentityMgtServiceExceptionException
The exception provides no meaningful message.
The wso2carbon log clearly logs the problem as:
"ERROR - Password pattern policy violated. Password should contain a digit[0-9], a lower case letter[a-z], an upper case letter[A-Z], one of !##$%&* characters {org.wso2.carbon.identity.mgt.IdentityMgtEventListener}"
Shouldn't the SOAP service return some useful information regarding the invalid password? As it is, I can not assume that the exception thrown is unique to invalid passwords and provide a meaningful message on the client side.
Is this a bug? Is there any way I can get an appropriate message from the soap service?
Thanks.
Ben
I know this is old, but I just finished setting up this same scenario.
It isn't a bug, exactly. Just their choice of implementation. I agree that out of box their error messages are lacking. Rather than fiddle with the SOAP response to get an error message to return in this instance, just add some javascript text validation on the client side.
<script type="text/javascript">
var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!##$%&*])/;
function doSubmit() {
var pass = document.getElementById("password").value
var confPass = document.getElementById("confirmPassword").value
if (pass != confPass) {
alert('Password do not match. Please correct');
}
else if (!re.test(pass)){
alert('Password must contain at least one lowercase letter, an uppercase letter, a number, and one of (!##$%&*). Please correct');
}
else {
document.getElementById("resetPasswordForm").submit();
}
}

ldap_search function returns errorcode 10 using c++ Win32 api?

i am using ldap functions to get user attributes value using win32 api.
the user name is arun.
in ldap_functions like init,set_options,connect,bind is succeed.but ldap search function is returned error code 10.
here my code
errorCode = ldap_search_s(
pLdapConnection, // Session handle
pMyDN, // DN to start search
LDAP_SCOPE_SUBTREE, // Scope LDAP_SCOPE_BASE LDAP_SCOPE_SUBTREE
pMyFilter, // Filter
NULL, // Retrieve list of attributes
0, // Get both attributes and values
&pSearchResult);
in pMyDN specified `"DC=SANJU,DC=CO,DC=IN"...
the return code 10 gives error is LDAP_REFERRAL.but i cant get it.
But i put pMyDN value into "OU=Marketing,DC=SANJU,DC=CO,DC=IN"
Now,search function succeed,So what is the problem?
i need this function without using OU,
can anyone help?
LDAP_REFERRAL: sent by Directory Server if the given base DN is an entry not handled by the current server and if the referral URL identifies a different server to handle the entry.
whether DNS and AD in different URL(IP) without trusted rule,this problem will occured.
LDAP response do not use error codes, they use result codes - so called because non-zero responses aren't necessarily errors. 10 is a case in point, it's a referral. The referral will contain information about the server which can process the request. If a directory proxy server is not in place to follow the referral, the LDAP client must follow the referral for itself.
Compare operation responses also use result codes to transmit the result of a compare.

WinAPI NetUserGetInfo() fails with NERR_UserNotFound error code on Active Directory domain

I'm running the following piece of code from a local service application. The purpose is to obtain the path to a user's profile before calling LoadUserProfile() to load that user's profile before calling CreateProcessAsUser() to run a user-mode process on behalf of that user.
Note that this question is not about LoadUserProfile(), or CreateProcessAsUser().
What happens is this. When the code below is run on Windows XP w/SP3 that is a part of the Active Directory domain, with a single user logged in via a local console (that user's session ID is used below) the NetUserGetInfo() API fails. Also note that it works fine in any other circumstance:
//'dwSessID' = session ID of the user to retrieve a user profile path for
LPTSTR pUserName = NULL;
DWORD dwcbSzUserName = 0;
if(!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessID, WTSUserName, &pUserName, &dwcbSzUserName))
{
//Error
return false;
}
USER_INFO_4* pUI4 = NULL;
DWORD dwNetStatus;
if((dwNetStatus = NetUserGetInfo(NULL, pUserName, 4, (BYTE**)&pUI4)) == NERR_Success)
{
PROFILEINFO pfi = {0};
pfi.dwSize = sizeof(pfi);
pfi.lpUserName = pUserName;
pfi.dwFlags = PI_NOUI;
pfi.lpProfilePath = pUI4->usri4_profile;
LoadUserProfile(hToken, &pfi);
//And so on
}
else
{
//On that specific machine I get here with 'dwNetStatus' = 2221,
//or NERR_UserNotFound, that according to MSDN is
//"The user name could not be found."
//Also note that GetLastError is not used for this API.
}
Can some suggest why can NetUserGetInfo() fail on that particular machine, and how to fix this code?
PS. I know that MSDN for NetUserGetInfo states that there might be issues with a ACL on Active Directory domain, but it doesn't specify how to set one...
If I read the documentation for NetUserGetInfo, for the information level of the data you code 4 . It's written Level 4 Return detailed information and additional attributes about the user account. This level is valid only on servers. As far as I understand it's not your case. Do you verify the value of pUserName returned by WTSQuerySessionInformation.
As JPBlanc stated NetUserGetInfo with level 4 is valid only on servers.
Another problem is that you retrieve the name of the logged on user, but not the domain the user belongs to.
Noticed you are calling NetUserGetInfo with pUserName the type of LPTSTR.
Sometimes it won't work (if you will compile your project to use ANSII strings by default).
Consider changing you string types to LPWSTR.