Connect to Wildfly Elytron's Credential Store with Masked Password - java

I have a credential store that I created with Elytron's tool giving a clear text password: "mypassword". In my Java program I can connect to the store with the following code;
Password storePassword = ClearPassword.createRaw(ClearPassword.ALGORITHM_CLEAR,"mypassword");
CredentialStore.ProtectionParameter protectionParameter = new CredentialStore.CredentialSourceProtectionParameter(
IdentityCredentials.NONE.withCredential(new PasswordCredential(storePassword)));
Provider provider = new WildFlyElytronPasswordProvider();
Security.addProvider(provider);
CredentialStore credentialStore = CredentialStore.getInstance(KeyStoreCredentialStore.KEY_STORE_CREDENTIAL_STORE);
// Configure and Initialise the CredentialStore
String configPath = System.getProperty("jboss.server.data.dir");
Map<String, String> configuration = new HashMap<>();
String path = configPath + File.separator + "credentials" + File.separator + "csstore.jceks";
configuration.put("keyStoreType", "JCEKS");
configuration.put("location", path);
configuration.put("modifiable", "false");
//Initialize credentialStore
credentialStore.initialize(configuration, protectionParameter);
However, I now want to connect to the credential store with an encrypted password instead of a clear text. For this purpose, I again used Elytron's tool to create a Masked Passowrd of "mypassword" with the following command;
elytron-tool.sh mask --salt 12345678 --iteration 123 --secret mypassword;
Here the values for salt and iteration are just random, could be anything. The above command gives me the masked password which is;
MASK-38PaKyS.9hHaRq7pAaE5tB;12345678;123
I now need a way to connect to credential store with this masked password within my Java program. I found that there is also a class called "MaskedPassword" which I might use but I couldn't find out how.
Any suggestions?

When you use elytron tool to generate masked password then you get string with prefix MASK- and suffix with salt and iteration
in your case - MASK-38PaKyS.9hHaRq7pAaE5tB;12345678;123
you can use below piece of code to decrypt the masked password,
private char[] getUnmaskedPass(String maskedPassword) throws GeneralSecurityException {
int maskLength = enter code here"MASK-".length();
if (maskedPassword == null || maskedPassword.length() <= maskLength) {
throw new GeneralSecurityException();
}
String[] parsed = maskedPassword.substring(maskLength).split(";");
if (parsed.length != 3) {
throw new GeneralSecurityException();
}
String encoded = parsed[0];
String salt = parsed[1];
int iteration = Integer.parseInt(parsed[2]);
PasswordBasedEncryptionUtil encryptUtil = new PasswordBasedEncryptionUtil.Builder().picketBoxCompatibility().salt(salt).iteration(iteration)
.decryptMode().build();
return encryptUtil.decodeAndDecrypt(encoded);
}
Now you can use this in your piece of code as a clearPassword. I hope that helped.
Source - https://github.com/wildfly-security/wildfly-elytron-tool/blob/master/src/main/java/org/wildfly/security/tool/MaskCommand.java static char[] decryptMasked(String maskedPassword)

We can create it using the below code...
Password storePassword = MaskedPassword.createRaw(MaskedPassword.ALGORITHM_MASKED_MD5_DES, <CREDENTIAL_STORE_ENTRY_PREFIX>.toCharArray(), 120,"12345678".getBytes(StandardCharsets.UTF_8),"MASK-38PaKyS.9hHaRq7pAaE5tB".getBytes(StandardCharsets.UTF_8));
....
....

Related

Update user password with LDAP when the user has the flag 'User must change password at next logon' set, leads to error 49, subcode 773

When I try to change the password of a user via LDAP, in whose AD account the setting is set that the password must be changed at the next login, I get the following error:
cause: javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090447, comment: AcceptSecurityContext error, data 773, v3839
Subcode 773 indicates that the user must reset the password, which is exactly what I intend to do right now.
With the following code I can successfully change the password if the above flag is not set:
public void updateUserPassword(String user, String oldPassword,
String newPassword) throws NamingException, LoginException {
try {
InitialDirContext ctx = this.getContext();
String filter = "(&(objectClass=user)(sAMAccountName=" + user + "))";
String baseDn = (String) this.getActiveDirectoryProps().get("baseDN_User");
// Search for user entry
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
ctls.setReturningObjFlag(true);
String[] returnAttrs = new String[3];
returnAttrs[0] = "cn"; // Common Name
returnAttrs[1] = "displayName";
returnAttrs[2] = "description";
NamingEnumeration<SearchResult> enumSearchResult = ctx.search(baseDn, filter, returnAttrs, ctls);
if (enumSearchResult.hasMore()) {
SearchResult result = enumSearchResult.next();
DirContext userCtx = (DirContext) result.getObject();
// Change the BindUser
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userCtx.getNameInNamespace());
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, oldPassword);
// Update password
Attribute oldattr = new BasicAttribute("unicodePwd", toUnicodeBytes(oldPassword));
Attribute newattr = new BasicAttribute("unicodePwd", toUnicodeBytes(newPassword));
ModificationItem olditem = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, oldattr);
ModificationItem newitem = new ModificationItem(DirContext.ADD_ATTRIBUTE, newattr);
String dn = userCtx.getNameInNamespace();
ctx.modifyAttributes(dn, new ModificationItem[]{olditem, newitem});
}
ctx.close();
} catch (final NamingException nE) {
//
} catch (Exception E) {
//
} finally {
//
}
}
So, do you have any idea what needs to be changed? Or what the reason is that it does not work?
My guess is that you just need to remove these lines:
// Change the BindUser
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userCtx.getNameInNamespace());
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, oldPassword);
You can't authenticate with the old password since it's no longer valid. But you also don't need to bind with the user's own credentials when changing the password, since you have to provide the old password in the request.
These lines may give you trouble too:
Attribute oldattr = new BasicAttribute("unicodePwd", toUnicodeBytes(oldPassword));
Attribute newattr = new BasicAttribute("unicodePwd", toUnicodeBytes(newPassword));
The passwords do have to converted to unicode bytes, but they also have to be enclosed in double quotes too ("). So you'll probably have to add double quotes before passing it to toUnicodeBytes().
You can manage it in two steps:
In case "user must change password" it set, you should change the password of the user to an initial password as admin (bind).
Attribute oldattr = new BasicAttribute("unicodePwd", toUnicodeBytes(oldPassword));
Attribute newattr = new BasicAttribute("unicodePwd", toUnicodeBytes(initialPassword));
Then, after a bind with the user with the (initial) password the user (himself) should change his password.
Attribute oldattr = new BasicAttribute("unicodePwd", toUnicodeBytes(initialPassword)));
Attribute newattr = new BasicAttribute("unicodePwd", toUnicodeBytes(newPassword));
(with double quotes, if you like)
This can work also in case if the user's password is expired.

I am unable to send email to recipient with Field Locators

I am not able to send email(s), I've tried with my real email and I haven't received any emails. How do I get this to work? I am not getting any errors.
Doesn't Docusign have a clean working java example on how to send a PDF file with Field Locator(s) to be signed by recipient. I got this sample code from Docusign:
// Enter your DocuSign credentials
String UserName = "myUserName#hotmail.com";
String Password = "MyPassword";
String IntegratorKey = "c8ad614b-def7-4631-aede-c90e68ef84d4";
// specify a document we want signed
String SignTest1File = "C:/Users/Public/test/TEST.PDF";
// enter recipient (signer) name and email
String recipientName = "Recipient Name";
String recipientEmail = "RecipientEmail#yahoo.com";
// for production environment update to "www.docusign.net/restapi"
String BaseUrl = "https://demo.docusign.net/restapi";
// initialize the api client for the desired environment
ApiClient apiClient = new ApiClient();
apiClient.setBasePath(BaseUrl);
// create JSON formatted auth header
String creds = "{\"Username\":\"" + UserName + "\",\"Password\":\"" + Password + "\",\"IntegratorKey\":\"" + IntegratorKey + "\"}";
apiClient.addDefaultHeader("X-DocuSign-Authentication", creds);
// assign api client to the Configuration object
Configuration.setDefaultApiClient(apiClient);
// create an empty list that we will populate with accounts
List<LoginAccount> loginAccounts = null;
try
{
// login call available off the AuthenticationApi
AuthenticationApi authApi = new AuthenticationApi();
// login has some optional parameters we can set
AuthenticationApi.LoginOptions loginOps = authApi.new LoginOptions();
loginOps.setApiPassword("true");
loginOps.setIncludeAccountIdGuid("true");
LoginInformation loginInfo = authApi.login(loginOps);
// note that a given user may be a member of multiple accounts
loginAccounts = loginInfo.getLoginAccounts();
System.out.println("LoginInformation: " + loginAccounts);
}
catch (com.docusign.esign.client.ApiException ex)
{
System.out.println("Exception: " + ex);
}
// create a byte array that will hold our document bytes
byte[] fileBytes = null;
try
{
//String currentDir = System.getProperty("user.dir");
// read file from a local directory
//Path path = Paths.get(currentDir + SignTest1File);
Path path = Paths.get(SignTest1File);
fileBytes = Files.readAllBytes(path);
}
catch (IOException ioExcp)
{
// handle error
System.out.println("Exception: " + ioExcp);
return;
}
// create an envelope that will store the document(s), tabs(s), and recipient(s)
EnvelopeDefinition envDef = new EnvelopeDefinition();
envDef.setEmailSubject("[Java SDK] - Please sign this doc");
// add a document to the envelope
Document doc = new Document();
String base64Doc = Base64.getEncoder().encodeToString(fileBytes);
doc.setDocumentBase64(base64Doc);
doc.setName("TestFile.pdf"); // can be different from actual file name
doc.setDocumentId("1");
List<Document> docs = new ArrayList<Document>();
docs.add(doc);
envDef.setDocuments(docs);
// add a recipient to sign the document, identified by name and email we used above
Signer signer = new Signer();
signer.setName(recipientName);
signer.setEmail(recipientEmail);
signer.setRecipientId("1");
// to embed the recipient you must set their |clientUserId| property!
signer.setClientUserId("1234");
// create a signHere tab somewhere on the document for the signer to sign
// default unit of measurement is pixels, can be mms, cms, inches also
SignHere signHere = new SignHere();
signHere.setDocumentId("1");
signHere.setPageNumber("1");
signHere.setRecipientId("1");
signHere.setXPosition("100");
signHere.setYPosition("150");
// can have multiple tabs, so need to add to envelope as a single element list
List<SignHere> signHereTabs = new ArrayList<SignHere>();
signHereTabs.add(signHere);
Tabs tabs = new Tabs();
tabs.setSignHereTabs(signHereTabs);
signer.setTabs(tabs);
// add recipients (in this case a single signer) to the envelope
envDef.setRecipients(new Recipients());
envDef.getRecipients().setSigners(new ArrayList<Signer>());
envDef.getRecipients().getSigners().add(signer);
// send the envelope by setting |status| to "sent". To save as a draft set to "created"
envDef.setStatus("sent");
// accountId is needed to create the envelope and for requesting the signer view
String accountId = null;
String envelopeId = null;
try
{
// use the |accountId| we retrieved through the Login API to create the Envelope
accountId = loginAccounts.get(0).getAccountId();
// instantiate a new EnvelopesApi object
EnvelopesApi envelopesApi = new EnvelopesApi();
// call the createEnvelope() API to send the signature request!
EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envDef);
// save the |envelopeId| that was generated and use in next API call
envelopeId = envelopeSummary.getEnvelopeId();
System.out.println("EnvelopeSummary: " + envelopeSummary);
}
catch (com.docusign.esign.client.ApiException ex)
{
System.out.println("Exception: " + ex);
}
// use the |accountId| we retrieved through the Login API and the |envelopeId| that was generated during envelope creation
accountId = loginAccounts.get(0).getAccountId();
// instantiate a new EnvelopesApi object
EnvelopesApi envelopesApi = new EnvelopesApi();
// set the url where you want the recipient to go once they are done signing
RecipientViewRequest returnUrl = new RecipientViewRequest();
returnUrl.setReturnUrl("https://www.docusign.com/devcenter");
returnUrl.setAuthenticationMethod("email");
// recipient information must match embedded recipient info we provided in step #2
returnUrl.setUserName(recipientName);
returnUrl.setEmail(recipientEmail);
returnUrl.setRecipientId("1");
returnUrl.setClientUserId("1234");
try
{
// call the CreateRecipientView API then navigate to the URL to start the signing session
ViewUrl recipientView = envelopesApi.createRecipientView(accountId, envelopeId, returnUrl);
System.out.println("ViewUrl: " + recipientView);
}
catch (com.docusign.esign.client.ApiException ex)
{
System.out.println("Exception: " + ex);
}
You are setting below attribute in your code, which is making this recipient an embedded signer. If you set clientUserId then you are telling DocuSign that treat this signer as embedded signer, and for embedded Signers DocuSign does not send any email for starting the signing ceremony. If you do not set clientUserId then DocuSign treats it as remote Signers and you will receive an email to start the Signing ceremony.
signer.setClientUserId("1234");
Code Example shows how to request an ESignature via an Email, and check Embedded Signing Example for embedded signing or Signing from Your App.

reading two variable values after decrypting

I am working on "Forgot Password". I am trying to create a reset token with email + current_time. email is user login whilst code will check if time >= 5 minutes then this link will not work. Here is my code:
// preparing token email + time
Date now = new Date();
String prepareToken = "?email="+email+"&tokenTime="+now.getTime();
// encrypt prepareToken value
Encryptor enc = new Encryptor();
resetToken = enc.encrypt(resetToken);
The token will be sent as for example as http://domainname.com/ForgotPassword?resetToken=adj23498ljj238809802340823
Problem:
When user click it then I got as request parameter and obviously decrypt this parameter but how can I get email in one String + time as another String
Please advise
If your issue is simply parsing the decoded String to get some sort of Map of your parameters, I'd suggest you to read Parse a URI String into Name-Value Collection .
Hope it helps.
EDIT :
Assuming you have the splitQuery(URL url) method from the previous link and that you successfully decoded the token :
public String getEmailFromToken(String decodedToken) {
// if you decoded your token it will looks like the prepareToken String
String stubUrl = "http://localhost"+decodedToken;
Map<String,String> map = splitQuery(new URL(stubUrl));
return map.get("timeToken");
}
I created a properly formed URL to respect the URL syntax.
With little tweak, you should be able to implement splitQuery for a String. I hope you can manage that.

Get decrypted LDAP pwdhistory values using Java

String[] userAttrList = {"cn", "sn","pwdHistory};
SearchResult searchResult = lc.search(baseDN, SearchScope.SUB, searchFilter, userAttrList);
List<SearchResultEntry> result = searchResult.getSearchEntries();
for (SearchResultEntry sre : result) {
value = sre.getAttributeValue("pwdHistory");
System.out.println(sre.getAttributeValue("pwdHistory"));
return value; }
I'm using unboundidsdk to get the user's details from LDAP.
Attribute(name=cn, values={'Test User'}),
Attribute(name=sn, values={'User'}),
Attribute(name=pwdHistory, values={'20150902093503Z#2.5.4.35#32#{AES256}33243DD8jnwa8a8asbaaa==', '20150903091818Z#2.5.4.35#32#{AES256}PJiYUi+ssasassasaasa==', '20150902090417Z#2.5.4.35#32#{AES256}asasasAAA222221211221=='})}, controls={})]
I get the password history in the LDAP default encrypted form.
Is there an API available to get it in a decrypted format?
get decrypted pwdHistory values
You can't, because they aren't encrypted is the first place. They are hashed.
Any system that allows you to retreive passwords in plaintext is ill-designed. OpenLDAP isn't one of them.

How to parse property value in properties file

Hi
I am loading a property file to establish DB connection,
ex:
DB1="JDBc................", username , password
above line is as in property file, but when i call getConnection method I need to send url, username and pw.
How can I parse it.
You can put your key/value pairs in a properties file like this:
dbUrl = yourURL
username = yourusername
password = yourpassword
Then you can load them into your app from the properties file:
private void loadProps() {
try {
InputStream is = getClass().getResourceAsStream("database_props.properties");
props = new Properties();
props.load(is);
is.close();
dbConnStr = props.getProperty("dbUrl");
username = props.getProperty("username");
password = props.getProperty("password");
}
catch(IOException ioe) {
log.error("IOException in loadProps");
for(StackTraceElement ste : ioe.getStackTrace())
log.error(ste.toString());
}
}
And then you can use those values to create your connection.
You can split the entry:
String dbProperty = prop.getProperty("DB1");
String[] dbDetails = dbProperty.split(",", 3);
dbDetails[0] will hold your JDBC..., [1] your username and [2] your password
Better still, you might want to hold them in different properties (As lweller said)
db.username = scott
db.password = tiger
db.url = ....
This way you get better clarity and control.
It is better to define separately
dburl =....
username =....
password = ...
Still if you want to parse it, you can use the split method of string to split by comma

Categories