I would like to know if it’s possible to store and retrieve credentials to/from Windows Credential Manager for my own application - I don’t need access to others, only to my own.
Or do you advise a different way to store credentials securely?
I would like to know if it’s possible to store and retrieve credentials to/from Windows Credential Manager for my own application - I don’t need access to others, only to my own.
Or do you advise a different way to store credentials securely?
Hi,
Not sure if this helps, but I think it might?
The Chilkat library includes a a few base classes dedicated to Certificates, Certificate Chains and Certificate Stores - including the Windows Certificate store.
We provide a Clarion Wrapper class for the Chilkat library too. More info can be found here:-
Chilkat CertStore help -
https://www.chilkatsoft.com/refdoc/xChilkatCertStoreRef.html
noyantis Wrapper template -
Hope it helps,
Thanks,
Andy
noyantis.com
Not looking for the Certificate Store - but the Credentials Store/Manager
Ah sorry, my mistake - reading what I wanted rather than what’s there lol
I think Secwin uses encrypted tables. CapeSoft Secwin
Not exactly a cheap way to go, especially with the additional pre-requisite addons, but it’s a feature-rich investment.
For securely storing info in our apps, we encrypt all sensitive data (using the Chilkat crypt2 base class) and then store them either in our tables and / or in external json files.
For the external json files, we use the Chilkat Json Object base class to create, read, write etc…
The reason for using external Json files was at the request of a customer, they wanted to be able to look at “config” type files easily, but of course not see any sensitive data (hence parts of it being encrypted).
Anyway, that’s one way you could store + retrieve the info…
Thanks,
Andy
noyantis.com
So simply said, there’s no easy way to interact with Windows Credential Manager as everyone keeps recommending other stuff?
Off the top of my head - not an easy way.
I think you’re probably looking at either a 3rd Party tool, or Windows API calls and creating the functionality yourself.
Sorry
There is a Clarion Live open webinar starting in around 25 mins… I’ll ask the question for you during the webinar - just in case anybody has done it without using 3rd party tools.
Cheers,
Andy
noyantis.com
Thank you for asking it in the Webinar!
Hi,
It really is as we thought, without external tools then you would have to code it yourself via Windows API calls.
Thanks,
Andy
noyantis.com
There is a Credentials Management API (I think it is a set of com interfaces).
Also there is a Data Protection API (DPAPI) which is implemented in EasyDotNet in TProtectedData class.
Might this help…
Thanks for that - currently in the process of finding the correct matching types for everything in Clarion - is there any known mapping out there between Clarion en C++ which is more up to date than the one on clarion.help?
https://clarion.help/doku.php?id=resolving_data_types.htm
Still trying to match the structure - anyone know how to resemble the LPSTR (CHAR *) in a Group?
I tried *CSTRING,RAW
as noted here: resolving_data_types.htm [Clarion Community Help] but it seems that Clarion isn’t accepting that
typedef struct _CREDENTIALA {
DWORD Flags;
DWORD Type;
LPSTR TargetName;
LPSTR Comment;
FILETIME LastWritten;
DWORD CredentialBlobSize;
LPBYTE CredentialBlob;
DWORD Persist;
DWORD AttributeCount;
PCREDENTIAL_ATTRIBUTEA Attributes;
LPSTR TargetAlias;
LPSTR UserName;
} CREDENTIALA, *PCREDENTIALA;
My currently tried group:
WindowsCredentialAttributes GROUP,TYPE
Keyword *CSTRING,RAW
Flags LONG
ValueSize LONG
Value BYTE
END
WindowsCredential GROUP,TYPE
Flags LONG
Type LONG
TargetName *CSTRING(WindowsCredential_MAX_STRING_LENGTH),RAW
Comment *CSTRING(WindowsCredential_MAX_STRING_LENGTH),RAW
LastWritten LONG
CredentialBlobSize LONG
CredentialBlob BYTE
Persist LONG
AttributeCount LONG
Attributes LIKE(WindowsCredentialAttributes)
TargetAlias *CSTRING(WindowsCredential_MAX_STRING_LENGTH),RAW
UserName *CSTRING(WindowsCredential_MAX_STRING_LENGTH),RAW
END
I also tried without * and RAW
and then it compiles, but when using the group this way with the API - I get an INVALID PARAMETER ERROR - so I guess, something isn’t decoded/coded correctly
I remember it this way … “LPSTR = long pointer to a string”, API strings are often null terminated, so I declare like this:
szTargetName CSTRING(128)
lpszTargetName LONG
and code like this:
szTargetName = 'myName'
lpszTargetName = ADDRESS(szTargetName)
If you were to adopt this, you would declare a szTargetName outside the group, then your group declaration would be thus:
WindowsCredential GROUP,TYPE
Flags LONG
Type LONG
lpszTargetName LONG
lpszComment LONG
.
Sadly I am still getting the “Parameter invalid error (87)” even if I change that
What is giving that error, calling one of the API functions?
Perhaps share the prototyping of the function being called.
Yeah it’s the function being called, I’ll share some code below:
Before Global INCLUDEs
WindowsCredential_MAX_STRING_LENGTH EQUATE(256);
LPSTR EQUATE(LONG);
WindowsCredentialAttributes GROUP,TYPE
Keyword LPSTR
Flags LONG
ValueSize LONG
Value BYTE
END
WindowsCredential GROUP,TYPE
Flags LONG
Type LONG
TargetName LPSTR
Comment LPSTR
LastWritten LONG
CredentialBlobSize LONG
CredentialBlob BYTE
Persist LONG
AttributeCount LONG
Attributes LIKE(WindowsCredentialAttributes)
TargetAlias LPSTR
UserName LPSTR
END
WindowsCredential_Flags_Prompt_Now EQUATE(0x1);
WindowsCredential_Flags_Username_Target EQUATE(0x2);
WindowsCredential_TYPE_GENERIC EQUATE(0x1);
WindowsCredential_TYPE_DOMAIN_PASSWORD EQUATE(0x2);
WindowsCredential_TYPE_DOMAIN_CERTIFICATE EQUATE(0x3);
WindowsCredential_TYPE_DOMAIN_VISIBLE_PASSWORD EQUATE(0x4);
WindowsCredential_TYPE_GENERIC_CERTIFICATE EQUATE(0x5);
WindowsCredential_TYPE_DOMAIN_EXTENDED EQUATE(0x6);
WindowsCredential_TYPE_MAXIMUM EQUATE(0x7);
WindowsCredential_TYPE_MAXIMUM_EX EQUATE(WindowsCredential_TYPE_MAXIMUM+1000);
WindowsCredential_PERSIST_SESSION EQUATE(0x1);
WindowsCredential_PERSIST_LOCAL_MACHINE EQUATE(0x2);
WindowsCredential_PERSIST_ENTERPRISE EQUATE(0x3);
Global Data
SFTPCredential LIKE(WindowsCredential)
Inside the Global Map
MODULE('Advapi32')
CredWriteW(*WindowsCredential Credential, LONG Flags),BOOL,RAW,PASCAL,NAME('CredWriteW')
CredReadW(LONG TargetName, LONG Type, LONG Flags, *WindowsCredential Credential),BOOL,RAW,PASCAL,NAME('CredReadW')
CredFree(LONG Buffer),RAW,PASCAL,NAME('CredFree')
END
My main procedure - Data Section
SFTPCredentialTargetName CSTRING(WindowsCredential_MAX_STRING_LENGTH)
SFTPCredentialUserName CSTRING(WindowsCredential_MAX_STRING_LENGTH)
SFTPCredentialCredential STRING(WindowsCredential_MAX_STRING_LENGTH)
My main procedure - Processed Code
SFTPCredential.Type = WindowsCredential_TYPE_GENERIC;
SFTPCredentialTargetName = FOO/SFTP';
SFTPCredential.TargetName = ADDRESS(SFTPCredentialTargetName);
IF (ReadCredentials(SFTPCredentialTargetName, SFTPCredential.Type) = FALSE)
MESSAGE('Reading of credentials failed[' & GetLastError() & ']: ' & GetLastErrorMessage(GetLastError()));
POST(EVENT:CloseDown);
RETURN;
END
SFTPCredentialCredential = 'Welkom123';
SFTPCredential.CredentialBlobSize = LEN(SFTPCredentialCredential);
SFTPCredential.CredentialBlob = ADDRESS(SFTPCredentialCredential);
SFTPCredential.Persist = WindowsCredential_PERSIST_LOCAL_MACHINE;
SFTPCredentialUserName = 'JohnDoe';
SFTPCredential.UserName = ADDRESS(SFTPCredentialUserName);
IF (WriteCredentials(0) = FALSE)
MESSAGE('Writing of credentials failed[' & GetLastError() & ']: ' & GetLastErrorMessage(GetLastError()));
POST(EVENT:CloseDown);
RETURN;
END
err … what happens inside WriteCredentials() ?
Also, you’ve prototyped CredWriteW and CredReadW, I think these will expect “Wide Chars”, aren’t there CredWriteA and CredReadA versions that expect ASCII?
Oops, forgot those, here you go:
!!! <summary>
!!! Generated from procedure template - Source
!!! </summary>
ReadCredentials PROCEDURE (*CSTRING targetName,LONG type) ! Declare Procedure
CODE
! SFTPCredential.TargetName = CLIP(targetName);
CLEAR(SFTPCredential);
SFTPCredential.TargetName = ADDRESS(targetName);
! UNLOCKTHREAD();
b# = CredReadW(SFTPCredential.TargetName, type, 0, SFTPCredential);
! LOCKTHREAD();
RETURN b#;
!!! <summary>
!!! Generated from procedure template - Source
!!! </summary>
WriteCredentials PROCEDURE (LONG flags) ! Declare Procedure
CODE
UNLOCKTHREAD();
b# = CredWriteW(SFTPCredential, flags);
LOCKTHREAD();
RETURN b#;
!!! <summary>
!!! Generated from procedure template - Source
!!! </summary>
FreeCredentials PROCEDURE ! Declare Procedure
CODE
UNLOCKTHREAD();
CredFree(ADDRESS(SFTPCredential));
LOCKTHREAD();
Oh, I’ll try the other Methods